<!-- 博客 - 页面布局 > 上中下 -->



<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=dark>
<!-- 博客 - 导航栏上方 -->


<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/blog/img/fluid.png">
  <link rel="icon" href="/blog/img/icon/dw.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Memory">
  <meta name="keywords" content="">

  
    <meta name="description" content="🍤 从入门到实践，一文介绍Docker的基本概念和常用命令，以及如何使用Docker部署自己的网站">
<meta property="og:type" content="article">
<meta property="og:title" content="Docker入门与实践：快速打造高效网站部署环境">
<meta property="og:url" content="https://test.atomgit.net/blog/2023/07/11/Docker%20%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E8%B7%B5%EF%BC%9A%E5%BF%AB%E9%80%9F%E6%89%93%E9%80%A0%E9%AB%98%E6%95%88%E7%BD%91%E7%AB%99%E9%83%A8%E7%BD%B2%E7%8E%AF%E5%A2%83/index.html">
<meta property="og:site_name" content="Memory&#39;s blog">
<meta property="og:description" content="🍤 从入门到实践，一文介绍Docker的基本概念和常用命令，以及如何使用Docker部署自己的网站">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://test.atomgit.net/blog/img/artical/forest.jpg">
<meta property="article:published_time" content="2023-07-11T10:44:08.000Z">
<meta property="article:modified_time" content="2025-06-05T15:59:29.000Z">
<meta property="article:author" content="Memory">
<meta property="article:tag" content="经验">
<meta property="article:tag" content="Docker">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://test.atomgit.net/blog/img/artical/forest.jpg">
  
  
  
  <title>Docker入门与实践：快速打造高效网站部署环境 - Memory&#39;s blog</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/blog/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/blog/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/blog/css/highlight-dark.css" />
  



  
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"test.atomgit.net","root":"/blog/","version":"1.9.4","typing":{"enable":true,"typeSpeed":100,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":false,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"appId":"T1hUHH9Ks1ggG9DBE3HgUPpV-gzGzoHsz","appKey":"XFkgzzvzNo3J3uNCbBiSOFKc","server_url":"https://t1huhh9k.lc-cn-n1-shared.com","path":"window.location.pathname","ignore_local":false}},"search_path":"/blog/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/blog/js/utils.js" ></script>
  <script  src="/blog/js/color-schema.js" ></script>
  

  

  

  

  

  

  

  



  
<meta name="generator" content="Hexo 5.4.2"></head>

<body>
  

  <header>
    <!-- 博客 - 导航栏上方 -->


<div class="header-inner" style="height: 100vh">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/blog/">
      <strong>Memory&#39;s blog</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/categories/">
                <i class="iconfont icon-category-fill"></i>
                <span>分类</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/tags/">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/about/">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/links/">
                <i class="iconfont icon-link-fill"></i>
                <span>友链</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/playlist/">
                <i class="iconfont icon-music"></i>
                <span>音乐</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/Memos/">
                <i class="iconfont icon-comment "></i>
                <span>说说</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/App/">
                <i class="iconfont icon-mobile"></i>
                <span>咫尺</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" target="_self" href="javascript:;" role="button"
                 data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="iconfont icon-books"></i>
                <span>青简</span>
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="http://47.93.135.62:5230/explore">
                    <i class="iconfont icon-images"></i>
                    <span>碎念微光</span>
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" href="/blog/New/">
                    <i class="iconfont icon-bug"></i>
                    <span>匠册详析</span>
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" href="/blog/New/">
                    <i class="iconfont icon-xbox-fill"></i>
                    <span>窗景新编</span>
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" href="/blog/New/">
                    <i class="iconfont icon-steam"></i>
                    <span>戏码幕后</span>
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" href="/blog/New/">
                    <i class="iconfont icon-map"></i>
                    <span>他山随拾</span>
                  </a>
                
              </div>
            </li>
          
        
        
            <li class="nav-item" id="search-btn">
                <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalNotice" aria-label="Search">
                    <i class="iconfont icon-book"></i>
                    <span>公告</span>
                </a>
            </li>
            
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>
 
<div id="banner" class="banner" parallax=true
     style="background: url('/blog/img/artical/forest.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">

    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">

        <div class="h2">
          
            <span id="subtitle" data-typed-text="Docker入门与实践：快速打造高效网站部署环境"></span>
          
        </div>


        
          <!-- 文章页面 - 顶部信息 -->

<div class="mt-3">
  
  <span class="post-meta mr-2">
    <i class="iconfont icon-author" aria-hidden="true"></i>
    Memory
  </span>
   
  <span class="post-meta">
    <i class="iconfont icon-date-fill" aria-hidden="true"></i>
    <time datetime="2023-07-11 18:44" pubdate>
      2023年7月11日 晚上
    </time>
  </span>
  
</div>

<div class="mt-1">
  
  <span class="post-meta mr-2">
    <i class="iconfont icon-chart"></i>
     32k 字 
  </span>
   
  <span class="post-meta mr-2">
    <i class="iconfont icon-clock-fill"></i>
       80 分钟 
  </span>
     
  <span
    id="leancloud-page-views-container"
    class="post-meta"
    style="display: none"
  >
    <i class="iconfont icon-eye" aria-hidden="true"></i>
    <span id="leancloud-page-views"></span> 次
  </span>

    
</div>


        

        <!-- 添加网站运行时间 -->
        <div class="footer-content" style="background-color: transparent;">
          <div>
            <span id="timeDate"></span>
            <span id="times"></span>
            <script>
            var now = new Date();
            function createtime(){
                var grt= new Date("03/07/2023 00:00:00");//此处修改你的建站时间或者网站上线时间
                now.setTime(now.getTime()+250);
                days = (now - grt ) / 1000 / 60 / 60 / 24;
                dnum = Math.floor(days);
                hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum);
                hnum = Math.floor(hours);
                if(String(hnum).length ==1 ){
                    hnum = "0" + hnum;
                }
                minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
                mnum = Math.floor(minutes);
                if(String(mnum).length ==1 ){
                          mnum = "0" + mnum;
                }
                seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
                snum = Math.round(seconds);
                if(String(snum).length ==1 ){
                          snum = "0" + snum;
                }
                document.getElementById("timeDate").innerHTML = "🚀 &nbsp"+dnum+"&nbsp天";  //此次自定义显示内容
                document.getElementById("times").innerHTML = hnum + "&nbsp小时&nbsp" + mnum + "&nbsp分&nbsp" + snum + "&nbsp秒";
            }  

            if (!window.location.href.includes('/20')) {  
            setInterval("createtime()", 250);  // 只有当URL不包含'specific-page'时，才调用createtime  
            }//此次自定义显示内容
            </script>
          </div>
        </div>

      </div>
      
        <div class="scroll-down-bar">
          <i class="iconfont icon-arrowdown"></i>
        </div>
      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      <!-- 文章页  -->


<div class="container-fluid nopadding-x">

  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar category-bar" style="margin-right: -1rem">
    <!-- 文章页面 - 左边栏所属分类 -->
  

<!-- 文章页 - 文章分类 -->





<div class="category-list">
  
  
    
    
    
    <div class="category row nomargin-x">
      <a class="category-item 
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="代码锋芒"
        id="heading-843238cb7c4b39b52e95311733ff6da6" role="tab" data-toggle="collapse" href="#collapse-843238cb7c4b39b52e95311733ff6da6"
        aria-expanded="true"
      >
        代码锋芒
        <span class="list-group-count">(31)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse show" id="collapse-843238cb7c4b39b52e95311733ff6da6"
           role="tabpanel" aria-labelledby="heading-843238cb7c4b39b52e95311733ff6da6">
        
        
          
          
  <div class="category-post-list">
    
    
      
      
        <a href="/blog/2023/03/19/MySQL%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE/" title="MySQL安装配置"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">MySQL安装配置</span>
        </a>
      
    
      
      
        <a href="/blog/2023/03/22/MySQL%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%85%A5%E5%9C%9F/" title="MySQL从入门到入土"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">MySQL从入门到入土</span>
        </a>
      
    
      
      
        <a href="/blog/2023/04/09/Java%E6%B3%9B%E5%9E%8B%E7%9A%84%E7%90%86%E8%A7%A3/" title="Java泛型：赋予灵活性的利器"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">Java泛型：赋予灵活性的利器</span>
        </a>
      
    
      
      
        <a href="/blog/2023/05/21/%E6%8E%A2%E7%B4%A2%20Python%20%E7%88%AC%E8%99%AB%E7%9A%84%E6%97%A0%E9%99%90%E5%8F%AF%E8%83%BD%E6%80%A7%EF%BC%9A%E5%9F%BA%E7%A1%80%E4%B8%8E%E5%BA%94%E7%94%A8/" title="探索Python爬虫的无限可能性：基础与应用"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">探索Python爬虫的无限可能性：基础与应用</span>
        </a>
      
    
      
      
        <a href="/blog/2023/06/03/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%20JavaWeb%20%E4%B9%8B%E6%97%85/" title="从零开始的 JavaWeb 之旅"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">从零开始的 JavaWeb 之旅</span>
        </a>
      
    
      
      
        <a href="/blog/2023/06/10/%E6%95%B0%E6%8D%AE%E5%BA%93-%E5%AE%8C%E6%95%B4%E6%80%A7%E7%BA%A6%E6%9D%9F/" title="数据库-完整性约束"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">数据库-完整性约束</span>
        </a>
      
    
      
      
        <a href="/blog/2023/06/24/%E4%BD%BF%E7%94%A8%20JSP%20%E6%9E%84%E5%BB%BA%20JavaWeb%20%E9%A1%B9%E7%9B%AE-%E4%BB%A5%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%A7%E4%BD%9C%E4%B8%9A%E4%B8%BA%E4%BE%8B/" title="使用JSP构建JavaWeb项目--以数据库大作业为例"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">使用JSP构建JavaWeb项目--以数据库大作业为例</span>
        </a>
      
    
      
      
        <a href="/blog/2023/07/06/%E6%89%93%E9%80%A0%E6%B5%81%E7%95%85%E7%BC%96%E7%A0%81%E4%B9%8B%E6%97%85%EF%BC%9AIntelliJ%20IDEA%20%E7%9A%84%E9%AB%98%E6%95%88%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7%E4%B8%8E%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B%E4%BC%98%E5%8C%96/" title="打造流畅编码之旅：IntelliJ IDEA 的高效使用技巧与工作流程优化"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">打造流畅编码之旅：IntelliJ IDEA 的高效使用技巧与工作流程优化</span>
        </a>
      
    
      
      
        <a href="/blog/2023/07/06/%E5%87%A4%E5%87%B0%E6%B6%85%E6%A7%83%EF%BC%9ASpring%20Boot%20%E5%BC%80%E5%8F%91%E4%B9%8B%E8%B7%AF%E4%B8%8A%E7%9A%84%E5%9D%8E%E5%9D%B7%E4%B8%8E%E6%88%90%E9%95%BF/" title="凤凰涅槃：Spring Boot 开发之路上的坎坷与成长"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">凤凰涅槃：Spring Boot 开发之路上的坎坷与成长</span>
        </a>
      
    
      
      
        <a href="/blog/2023/07/11/%E4%BB%8EIP%E5%88%B0Ping%E5%91%BD%E4%BB%A4%EF%BC%9A%E4%BA%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E7%9A%84%E5%9F%BA%E7%A1%80/" title="从IP到Ping命令：了解计算机网络连接的基础"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">从IP到Ping命令：了解计算机网络连接的基础</span>
        </a>
      
    
      
      
        <a href="/blog/categories/%E4%BB%A3%E7%A0%81%E9%94%8B%E8%8A%92/" class="list-group-item list-group-item-action">
          <span class="category-post">More...</span>
        </a>
        
  </div>

          
  
    
    
    
    <div class="category-sub row nomargin-x">
      <a class="category-subitem collapsed
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="职路星火"
        id="heading-59c550454d1ecf67a2ead26a1c46d14b" role="tab" data-toggle="collapse" href="#collapse-59c550454d1ecf67a2ead26a1c46d14b"
        aria-expanded="false"
      >
        职路星火
        <span class="list-group-count">(2)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse " id="collapse-59c550454d1ecf67a2ead26a1c46d14b"
           role="tabpanel" aria-labelledby="heading-59c550454d1ecf67a2ead26a1c46d14b">
        
        
          
  <div class="category-post-list">
    
    
      
      
        <a href="/blog/2024/03/07/%E7%A0%BA%E5%89%91%E5%87%BA%E9%9E%98%EF%BC%9A%E6%88%91%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%B8%88%E6%B1%82%E8%81%8C%E4%B9%8B%E6%97%85/" title="砺剑出鞘：我的软件工程师求职之旅"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">砺剑出鞘：我的软件工程师求职之旅</span>
        </a>
      
    
      
      
        <a href="/blog/2024/04/16/%E6%8B%A8%E4%BA%91%E8%A7%81%E6%97%A5%EF%BC%9A%E8%81%8C%E5%9C%BA%E7%94%9F%E6%B4%BB%E7%9A%84%E7%82%B9%E6%BB%B4%E8%AE%B0%E5%BD%95/" title="拨云见日：职场生活的点滴记录"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">拨云见日：职场生活的点滴记录</span>
        </a>
      
    
  </div>

        
      </div>
    </div>
  
    
    
    
    <div class="category-sub row nomargin-x">
      <a class="category-subitem 
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="部署之道"
        id="heading-36acf247b1a64f4bbe423776a392cfde" role="tab" data-toggle="collapse" href="#collapse-36acf247b1a64f4bbe423776a392cfde"
        aria-expanded="true"
      >
        部署之道
        <span class="list-group-count">(5)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse show" id="collapse-36acf247b1a64f4bbe423776a392cfde"
           role="tabpanel" aria-labelledby="heading-36acf247b1a64f4bbe423776a392cfde">
        
        
          
          
  <div class="category-post-list">
    
    
      
      
        <a href="/blog/2023/06/22/Nginx%20%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E7%90%86%E8%A7%A3%E3%80%81%E9%85%8D%E7%BD%AE%E5%92%8C%E4%BC%98%E5%8C%96/" title="Nginx 入门指南：理解、配置和优化"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">Nginx 入门指南：理解、配置和优化</span>
        </a>
      
    
      
      
        <a href="/blog/2023/07/11/Docker%20%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E8%B7%B5%EF%BC%9A%E5%BF%AB%E9%80%9F%E6%89%93%E9%80%A0%E9%AB%98%E6%95%88%E7%BD%91%E7%AB%99%E9%83%A8%E7%BD%B2%E7%8E%AF%E5%A2%83/" title="Docker入门与实践：快速打造高效网站部署环境"
           class="list-group-item list-group-item-action
           active">
          <span class="category-post">Docker入门与实践：快速打造高效网站部署环境</span>
        </a>
      
    
      
      
        <a href="/blog/2023/08/17/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%20API%20%E7%BD%91%E5%85%B3%EF%BC%9A%E5%8E%9F%E7%90%86%E3%80%81%E5%8A%9F%E8%83%BD%E5%92%8C%E7%94%A8%E9%80%94/" title="深入理解 API 网关：原理、功能和用途"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">深入理解 API 网关：原理、功能和用途</span>
        </a>
      
    
  </div>

          
  
    
    
    
    <div class="category-sub row nomargin-x">
      <a class="category-subitem collapsed
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="职路星火"
        id="heading-59c550454d1ecf67a2ead26a1c46d14b" role="tab" data-toggle="collapse" href="#collapse-59c550454d1ecf67a2ead26a1c46d14b"
        aria-expanded="false"
      >
        职路星火
        <span class="list-group-count">(2)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse " id="collapse-59c550454d1ecf67a2ead26a1c46d14b"
           role="tabpanel" aria-labelledby="heading-59c550454d1ecf67a2ead26a1c46d14b">
        
        
          
  <div class="category-post-list">
    
    
      
      
        <a href="/blog/2024/12/16/%E6%BC%AB%E6%BC%AB%E5%BE%81%E9%80%94%EF%BC%9A%E7%AD%91%E6%A2%A6%E4%BA%8E%E8%81%8C%E5%9C%BA%E9%A3%8E%E9%9B%A8%EF%BC%8C%E5%90%9F%E5%92%8F%E4%BA%8E%E6%97%A5%E5%B8%B8%E8%AF%97%E6%84%8F/" title="漫漫征途：筑梦于职场风雨，吟咏于日常诗意"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">漫漫征途：筑梦于职场风雨，吟咏于日常诗意</span>
        </a>
      
    
      
      
        <a href="/blog/2025/10/23/%E4%BF%9D%E9%A9%BE%E6%8A%A4%E8%88%AA%E2%80%94%E2%80%94%E5%90%8E%E5%8F%B0%E8%BF%90%E7%BB%B4%E8%A7%86%E8%A7%92%E4%B8%8B%E7%9A%84%E9%AB%98%E9%80%9F%E5%85%AC%E8%B7%AF%E2%80%9C%E7%94%9F%E5%91%BD%E7%BA%BF%E2%80%9D/" title="保驾护航——后台运维视角下的高速公路“生命线”"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">保驾护航——后台运维视角下的高速公路“生命线”</span>
        </a>
      
    
  </div>

        
      </div>
    </div>
  
        
      </div>
    </div>
  
    
    
    
    <div class="category-sub row nomargin-x">
      <a class="category-subitem collapsed
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="项目志录"
        id="heading-005e56101bc2a873707cb4461a70ded8" role="tab" data-toggle="collapse" href="#collapse-005e56101bc2a873707cb4461a70ded8"
        aria-expanded="false"
      >
        项目志录
        <span class="list-group-count">(1)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse " id="collapse-005e56101bc2a873707cb4461a70ded8"
           role="tabpanel" aria-labelledby="heading-005e56101bc2a873707cb4461a70ded8">
        
        
          
  <div class="category-post-list">
    
    
      
      
        <a href="/blog/2023/07/30/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB%EF%BC%9A%E8%B8%A9%E5%9D%91%E6%8C%87%E5%8D%97%E4%B8%8E%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93/" title="小程序开发经验分享：踩坑指南与技巧总结"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">小程序开发经验分享：踩坑指南与技巧总结</span>
        </a>
      
    
  </div>

        
      </div>
    </div>
  
        
      </div>
    </div>
  
</div>

  </aside>


    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Docker入门与实践：快速打造高效网站部署环境</h1>
            
              <p class="note note-success">
                
                  
                    本文最后更新于：6 个月前
                  
                
              </p>
            
            
              <div class="markdown-body">
                
                <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><ul>
<li><p>我很荣幸能够分享一篇关于 Docker 的博客笔记。</p>
</li>
<li><p>这些笔记真的非常值得学习和借鉴。通过阅读黑马程序员分享的优质内容，我深深地感受到了他们在技术分享方面的专业精神和对学习者的支持</p>
</li>
<li><p>对于想要深入了解 Docker 的人来说，这篇博客笔记提供了一个很好的学习资源。在这些笔记中，我们可以了解到<strong>Docker 的基本概念</strong>、<strong>工作原理</strong>以及<strong>如何搭建</strong>、<strong>使用</strong>和<strong>管理 Docker 容器</strong></p>
</li>
<li><p>这些知识对于我们在<strong>实际项目中的应用</strong>和<strong>技术提升</strong>有着巨大的帮助</p>
</li>
</ul>
<blockquote>
<h5 id="推荐阅读："><a href="#推荐阅读：" class="headerlink" title="推荐阅读："></a>推荐阅读：</h5></blockquote>
<blockquote>
<h5 id="听说很少有人将-Docker-讲懂？我来试试！-掘金-juejin-cn"><a href="#听说很少有人将-Docker-讲懂？我来试试！-掘金-juejin-cn" class="headerlink" title="听说很少有人将 Docker 讲懂？我来试试！ - 掘金 (juejin.cn)"></a><a target="_blank" rel="noopener" href="https://juejin.cn/post/7244810003591757882">听说很少有人将 Docker 讲懂？我来试试！ - 掘金 (juejin.cn)</a></h5><h5 id="课件：Docker-实用篇-掘金-juejin-cn"><a href="#课件：Docker-实用篇-掘金-juejin-cn" class="headerlink" title="课件：Docker 实用篇 - 掘金 (juejin.cn)"></a><a target="_blank" rel="noopener" href="https://juejin.cn/post/7270345842849988668">课件：Docker 实用篇 - 掘金 (juejin.cn)</a></h5></blockquote>
<h1 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a>Docker</h1><blockquote>
<p>2025 年 7 月 1 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/7424338056918777882">Docker 万字入门教程 Docker 使用 Google 公司推出的 Go 语言进行开发实现，对进程进行封装隔离，属于 - 掘金 (juejin.cn)</a></p>
<blockquote>
<p>2024 年 12 月 19 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_39135287/article/details/101012149">Docker 入门到实践 (一) docker 简介与安装_docker 与思政-CSDN 博客</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_39135287/article/details/102955902">Docker 入门到实践 (二) docker 常用命令讲解_docker 入门到实践 (二) docker 常用指令解说-CSDN 博客</a></p>
<blockquote>
<p>2025 年 1 月 15 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1701451">centos7 安装 Docker 详细步骤（无坑版教程）-腾讯云开发者社区-腾讯云 (tencent.com)</a></p>
<p><a target="_blank" rel="noopener" href="https://config.net.cn/server/microservice/c295646a-b68a-48b6-a0a3-a3c829e6a64d-p1.html">windows10+VMWare+Centos7 下 docker 的安装，验证与运行(超详细且持续更新) -配置啦-研发运维人员必备网站 (config.net.cn)</a></p>
<p><a target="_blank" rel="noopener" href="http://mirrors.aliyun.com/centos/">centos 安装包下载_开源镜像站-阿里云 (aliyun.com)</a></p>
<p><a target="_blank" rel="noopener" href="https://config.net.cn/server/microservice/c295646a-b68a-48b6-a0a3-a3c829e6a64d-p1.html">windows10+VMWare+Centos7 下 docker 的安装，验证与运行(超详细且持续更新) -配置啦-研发运维人员必备网站 (config.net.cn)</a></p>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/7203258813893345340">Docker 搭建 Minio 对象存储服务 MinIO MinIO 是一款基于 Go 语言发开的高性能、分布式的对象存储 - 掘金 (juejin.cn)</a></p>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/7165372823467196423">手摸手教你使用 Docker 快速搭建 Gitlab 服务本文在 CentOS 虚拟机中使用 Docker 快速搭建了一 - 掘金 (juejin.cn)</a></p>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/7146440835381329934">上手 Linux：安装 Git 的两种方式在 Linux 系统上安装软件有两种常用的方式。一种是下载源码 - 编译 - 安 - 掘金 (juejin.cn)</a></p>
<p>这篇挺全的：<a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1725379904230518786#heading-22">Springboot 整合 Minio 全流程 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<blockquote>
<p>2025 年 1 月 25 日</p>
</blockquote>
<p>今天实践操作下 docker，安装 Docker。</p>
<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p><strong>查看 CentOS 操作系统版本和 Linux 内核版本</strong>：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cat</span> /etc/redhat-release<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">uname</span> -r<br></code></pre></td></tr></table></figure>

<p><img src="http://blog.memory-life.xyz/image-20250125193326081.png" alt="image-20250125193326081"></p>
<p>可以看到 CentOS7 的操作系统为 x86_64(64 位)，系统内核版本为 3.10.0，没有问题。</p>
<p><strong>卸载旧版本。</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine<br></code></pre></td></tr></table></figure>

<p><img src="C:/Users/Lenovo/AppData/Roaming/Typora/typora-user-images/image-20250125193531866.png" alt="image-20250125193531866"></p>
<p><strong>安装 docker 所需的软件包</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum install -y yum-utils device-mapper-persistent-data lvm2<br></code></pre></td></tr></table></figure>

<p><strong>设置 yum 源为阿里云 (由于国外网站访问速度慢)</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo<br></code></pre></td></tr></table></figure>

<p><strong>更新 yum 软件包索引</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum makecache fast<br></code></pre></td></tr></table></figure>

<p><strong>安装 docker CE(社区版)，Docker 提供了两个版本：社区版(CE，免费) 和 企业版(EE，收费)</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum -y install docker-ce<br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_44700578/article/details/140881224">Linux 中 yum、rpm、apt-get、wget 的区别，yum、rpm、apt-get 常用命令，CentOS、Ubuntu 中安装 wget_apt-get 和 yum-CSDN 博客</a></p>
<p><img src="http://blog.memory-life.xyz/image-20250125194344413.png" alt="image-20250125194344413"></p>
<p>检查版本，是否安装成功。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker version<br></code></pre></td></tr></table></figure>

<p><img src="http://blog.memory-life.xyz/image-20250125194522470.png" alt="image-20250125194522470"></p>
<blockquote>
<p>2025 年 1 月 25 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_39135287/article/details/102955902">Docker 入门到实践 (二) docker 常用命令讲解_docker 入门到实践 (二) docker 常用指令解说-CSDN 博客</a></p>
<blockquote>
<p>2025 年 2 月 10 日</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum install -y yum-utils device-mapper-persistent-data lvm2<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">ping: mirrorlist.centos.org: Name or service not known<br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_46122805/article/details/143656526">CentOS7 yum 安装报错 “Could not resolve host: mirrorlist.centos.org； Name or service not known” 解决方法_ping: mirrorlist.centos.org: name or service not k-CSDN 博客</a></p>
<p>1、从阿里云下载新的配置文件，两个命令可用，如果虚拟机还没安装 wget 工具，就使用 curl</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo<br>curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo<br></code></pre></td></tr></table></figure>

<p>2、清理缓存</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum clean all<br></code></pre></td></tr></table></figure>

<p>3、重新生成缓存</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum makecache<br></code></pre></td></tr></table></figure>

<p>4、更新 yum 源包</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum -y update<br></code></pre></td></tr></table></figure>

<p>结束，更换 yum 源成功。</p>
<p>不过这个步骤属实多余，直接按照上面 Doker 安装的命令执行下来，安装 Docker 是相当顺利的。</p>
<h2 id="远程部署"><a href="#远程部署" class="headerlink" title="远程部署"></a>远程部署</h2><blockquote>
<p>2025 年 2 月 5 日</p>
</blockquote>
<p>已经十多天没有学习了吗。</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_62128476/article/details/144411765">Docker 为容器设置环境变量（在 docker run 命令中设置容器的环境变量、在 Dockerfile 文件中设置容器的环境变量、在 docker-compose.yaml 中设置容器的环境变量）_dockerfile 设置环境变量-CSDN 博客</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.51cto.com/u_16175488/11781019">java 获取 docker 环境变量_mob649e8161738c 的技术博客_51CTO 博客</a></p>
<p>新建一个 Web 项目，尝试下 Docker 部署。</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_36833673/article/details/145308820">docker 部署 java 项目详解-CSDN 博客</a></p>
<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/cuay/p/18501288">WAR 包和 JAR 包的区别 - 林泽阿 - 博客园 (cnblogs.com)</a></p>
<p><a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1776245631845789697#heading-4">IDEA+Docker 远程部署 Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 基础镜像</span><br><span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">8</span><br><span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br><span class="hljs-keyword">ADD</span><span class="language-bash"> target/hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">&quot;java&quot;</span>,<span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;/app.jar&quot;</span> , <span class="hljs-string">&quot;--spring.profiles.active=prod&quot;</span>]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br><span class="hljs-keyword">EXPOSE</span>  <span class="hljs-number">8080</span><br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1872492636669014017#heading-3">Docker 一键远程部署厚米匹配后端 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs angelscript"><span class="hljs-symbol">Dw990831@</span><br></code></pre></td></tr></table></figure>

<p>配置 Docker 一键部署：ssh 远程连接服务器，连接 Docker 守护进程，编写 Dockerfile 文件，配置远程部署。</p>
<p>ssh 远程连接服务器。</p>
<p><img src="http://blog.memory-life.xyz/image-20250205102013411.png" alt="image-20250205102013411"></p>
<p>连接 Docker 守护进程。</p>
<p><img src="http://blog.memory-life.xyz/image-20250205103921071.png" alt="image-20250205103921071"></p>
<p>编写 Dockerfile 文件。</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 基础镜像</span><br><span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">8</span><br><span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br><span class="hljs-keyword">ADD</span><span class="language-bash"> target/hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">&quot;java&quot;</span>,<span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;/app.jar&quot;</span>]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br><span class="hljs-keyword">EXPOSE</span>  <span class="hljs-number">8080</span><br></code></pre></td></tr></table></figure>

<p>配置远程部署。</p>
<p><img src="http://blog.memory-life.xyz/image-20250205103822292.png" alt="image-20250205103822292"></p>
<p><a target="_blank" rel="noopener" href="https://blog.51cto.com/u_16213317/11768523">怎么查看 docker 开放的端口通不通_mob64ca12d4a164 的技术博客_51CTO 博客</a></p>
<p>特么的，配置都完成了，就看最后一步能不能一键部署成功，结果好像是 Docker 连接失败了。</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_67497257/article/details/140822980">Docker 镜像的创建方法_docker 创建镜像-CSDN 博客</a></p>
<p>那就手动上传 jar 包和 Dockerfile 文件，先构建镜像再运行容器试试看。</p>
<p>学一学。</p>
<p>要构建一个 Docker 镜像，你需要确保你已经安装了 Docker，并且你的<code>Dockerfile</code>和<code>hello-0.0.1-SNAPSHOT.jar</code>文件在同一目录下。以下是如何使用 Docker 命令行工具来构建你的镜像的步骤：</p>
<ol>
<li><p><strong>打开命令行界面</strong>：</p>
<ul>
<li>在 Windows 上，你可以使用 PowerShell 或命令提示符。</li>
<li>在 macOS 或 Linux 上，打开你的终端。</li>
</ul>
</li>
<li><p><strong>导航到包含 Dockerfile 的目录</strong>：<br>使用<code>cd</code>命令导航到包含你的<code>Dockerfile</code>和<code>hello-0.0.1-SNAPSHOT.jar</code>文件的目录。例如：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">bash复制代码<br><br><span class="hljs-built_in">cd</span> path/to/your/directory<br></code></pre></td></tr></table></figure></li>
<li><p><strong>构建 Docker 镜像</strong>：<br>使用<code>docker build</code>命令来构建你的镜像。你需要为你的镜像指定一个标签（tag），这通常包括一个名称和一个版本号。例如：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">bash复制代码<br><br>docker build -t hello-app:0.0.1 .<br></code></pre></td></tr></table></figure>

<p>这里的<code>-t hello-app:0.0.1</code>指定了镜像的名称为<code>hello-app</code>和版本号为<code>0.0.1</code>。最后的<code>.</code>表示 Dockerfile 位于当前目录。</p>
</li>
<li><p><strong>验证镜像是否构建成功</strong>：<br>使用<code>docker images</code>命令来查看你的本地镜像列表，确认你的<code>hello-app:0.0.1</code>镜像已经成功构建。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">bash复制代码<br><br>docker images<br></code></pre></td></tr></table></figure></li>
<li><p><strong>运行 Docker 容器</strong>：<br>使用<code>docker run</code>命令来运行你的容器。例如：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">bash复制代码<br><br>docker run -d -p 8080:8080 hello-app:0.0.1<br></code></pre></td></tr></table></figure>

<p>这里的<code>-d</code>标志表示容器将在后台运行，<code>-p 8080:8080</code>将主机的 8080 端口映射到容器的 8080 端口。</p>
</li>
<li><p><strong>验证容器是否正在运行</strong>：<br>使用<code>docker ps</code>命令来查看正在运行的容器列表。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">bash复制代码<br><br>docker ps<br></code></pre></td></tr></table></figure></li>
<li><p><strong>访问你的应用</strong>：<br>打开你的网页浏览器，访问<code>http://localhost:8080</code>，你应该能够看到你的 Java 应用正在运行。</p>
</li>
</ol>
<p>试一试。</p>
<p>出问题了。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker build -f Dockerfile -t hello</span><br>ERROR: <span class="hljs-string">&quot;docker buildx build&quot;</span> requires exactly 1 argument.<br>See <span class="hljs-string">&#x27;docker buildx build --help&#x27;</span>.<br><br>Usage:  docker buildx build [OPTIONS] PATH | URL | -<br><br>Start a build<br>[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker build -t hello-app .</span><br>[+] Building 30.1s (2/2) FINISHED                                                                                                                                                docker:default<br> =&gt; [internal] load build definition from Dockerfile                                                                                                                                       0.0s<br> =&gt; =&gt; transferring dockerfile: 323B                                                                                                                                                       0.0s<br> =&gt; ERROR [internal] load metadata <span class="hljs-keyword">for</span> docker.io/library/openjdk:8                                                                                                                        30.0s<br>------<br> &gt; [internal] load metadata <span class="hljs-keyword">for</span> docker.io/library/openjdk:8:<br>------<br>Dockerfile:2<br>--------------------<br>   1 |     <span class="hljs-comment"># 基础镜像</span><br>   2 | &gt;&gt;&gt; FROM openjdk:8<br>   3 |     <span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br>   4 |     ADD target/hello-0.0.1-SNAPSHOT.jar app.jar<br>--------------------<br>ERROR: failed to solve: DeadlineExceeded: DeadlineExceeded: DeadlineExceeded: openjdk:8: failed to resolve <span class="hljs-built_in">source</span> metadata <span class="hljs-keyword">for</span> docker.io/library/openjdk:8: failed to <span class="hljs-keyword">do</span> request: Head <span class="hljs-string">&quot;https://registry-1.docker.io/v2/library/openjdk/manifests/8&quot;</span>: dial tcp 198.44.185.131:443: i/o <span class="hljs-built_in">timeout</span><br></code></pre></td></tr></table></figure>

<p>jar 包没有放在同级目录下啊。</p>
<p>算了，看来是基础镜像出问题了，吃完饭上来搞搞。</p>
<h2 id="镜像源修改"><a href="#镜像源修改" class="headerlink" title="镜像源修改"></a>镜像源修改</h2><p><a target="_blank" rel="noopener" href="https://blog.csdn.net/ZPC8210/article/details/145176508">docker hello world_docker 输出 hello word-CSDN 博客</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull hello-world<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker pull hello-world</span><br>Using default tag: latest<br>Error response from daemon: Get <span class="hljs-string">&quot;https://registry-1.docker.io/v2/&quot;</span>: net/http: request canceled <span class="hljs-keyword">while</span> waiting <span class="hljs-keyword">for</span> connection (Client.Timeout exceeded <span class="hljs-keyword">while</span> awaiting headers)<br>[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment">#</span><br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_51492817/article/details/140332408">Docker 修改国内镜像源_docker 更换国内镜像源-CSDN 博客</a></p>
<p>这篇写得很详细了：<a target="_blank" rel="noopener" href="https://blog.51cto.com/u_16213434/11776091">docker 切换国内镜像源_mob64ca12f10f72 的技术博客_51CTO 博客</a></p>
<p>使用 docker 命令行设置镜像源，不太好使。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo docker login --username=&lt;你的用户名&gt; registry.cn-hangzhou.aliyuncs.com<br></code></pre></td></tr></table></figure>

<p>得直接修改 Docker 的 daemon 配置文件。</p>
<p>步骤详解</p>
<p>步骤 1: 备份 Docker 的原始配置文件。</p>
<p>在对 Docker 的配置文件进行修改之前，我们需要先备份原始配置文件，以便在出现问题时能够恢复。</p>
<p>备份原始的配置文件到指定位置</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">cp</span> /etc/docker/daemon.json /etc/docker/daemon.json.bak<br></code></pre></td></tr></table></figure>

<p>代码解释：</p>
<ul>
<li><p>sudo：以超级用户权限执行命令。</p>
</li>
<li><p>cp：复制文件的命令。</p>
</li>
<li><p>/etc/docker/daemon.json：Docker 的默认配置文件路径。</p>
</li>
<li><p>/etc/docker/daemon.json.bak：备份文件的路径。</p>
</li>
</ul>
<p>步骤 2: 创建或编辑 Docker 的配置文件</p>
<p>确保 Docker 的配置文件存在，如果没有则需要创建一个新的。</p>
<p>检查配置文件是否存在</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo <span class="hljs-built_in">mkdir</span> -p /etc/docker/<br>sudo <span class="hljs-built_in">touch</span> /etc/docker/daemon.json<br></code></pre></td></tr></table></figure>

<p>代码解释：</p>
<ul>
<li><p>mkdir -p /etc/docker/：创建 Docker 配置目录，如果路径中已存在部分目录则不会报错。</p>
</li>
<li><p>touch /etc/docker/daemon.json：创建 daemon.json 文件，如果已存在则更新其时间戳。</p>
</li>
</ul>
<p>步骤 3: 修改镜像源为国内镜像</p>
<p>接下来，我们需要通过编辑 daemon.json 文件来添加国内的镜像源。这里以阿里云的 Docker 镜像为例。</p>
<p>开启编辑器（vi 或其它文本编辑器）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo vi /etc/docker/daemon.json<br></code></pre></td></tr></table></figure>

<p>在打开的 daemon.json 文件中填写以下内容：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">&#123;<br>  <span class="hljs-string">&quot;registry-mirrors&quot;</span>: [<br>    <span class="hljs-string">&quot;https://&lt;your_ali_cdn&gt;.mirror.aliyuncs.com&quot;</span><br>  ]<br>&#125;<br></code></pre></td></tr></table></figure>

<p>代码解释：</p>
<ul>
<li><p>registry-mirrors：这是配置镜像加速器的键，用于指定 Docker 镜像源的地址。</p>
</li>
<li><p>“https://<your_ali_cdn>.mirror.aliyuncs.com”：将 <your_ali_cdn> 替换为你在阿里云中获得的加速器地址。你也可以选择其他的国内镜像源，如网易、腾讯等。</p>
</li>
</ul>
<p>步骤 4: 重启 Docker 服务</p>
<p>完成镜像源的配置后，我们需要重启 Docker 服务使其生效。</p>
<p>重启 Docker 服务</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl daemon-reload<br>sudo systemctl restart docker<br></code></pre></td></tr></table></figure>

<p>代码解释：</p>
<ul>
<li><p>systemctl daemon-reload：重新加载服务配置。</p>
</li>
<li><p>systemctl restart docker：重启 Docker 服务。</p>
</li>
</ul>
<p>步骤 5: 验证镜像源是否修改成功</p>
<p>最后一步是验证配置是否成功。我们可以通过拉取一个镜像来检查。</p>
<p>测试拉取一个镜像（例如：hello-world）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull hello-world<br></code></pre></td></tr></table></figure>

<p>代码解释：</p>
<ul>
<li>docker pull hello-world：从 Docker 镜像源拉取 hello-world 镜像，用于测试。</li>
</ul>
<p>如果镜像能够快速拉取并成功完成，那么就表示你已成功切换至国内镜像源。</p>
<p><a target="_blank" rel="noopener" href="http://www.llxxkj.cn/content/1939.html">阿里云地域 Region ID? 地域及其 RegionID 对照表?_陆陆科技 (llxxkj.cn)</a></p>
<p><img src="http://www.llxxkj.cn/data/upload/2023-06-29/649d1f91988cd.png" alt="649d1f91988cd.png"></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">&#123;<br>  <span class="hljs-string">&quot;registry-mirrors&quot;</span>: [<br>    <span class="hljs-string">&quot;https://cn-beijing.mirror.aliyuncs.com&quot;</span><br>  ]<br>&#125;<br></code></pre></td></tr></table></figure>

<p>漂亮，对照这张表修改配置文件内容，直接执行拉取镜像命令，成功了。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ docker]<span class="hljs-comment"># docker pull hello-world</span><br>Using default tag: latest<br>latest: Pulling from library/hello-world<br>2db29710123e: Pull complete<br>Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f<br>Status: Downloaded newer image <span class="hljs-keyword">for</span> he<br></code></pre></td></tr></table></figure>

<p>那么跑一下这个镜像吧。</p>
<p>运行一个名为 <code>hello-world</code> 的镜像，容器名为 <code>helloworld</code>，将容器的 80 端口映射到主机的 8080 端口，并在后台运行：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -d -p 8080:80 --name helloworld hello-world:latest<br></code></pre></td></tr></table></figure>

<p>查看正在运行中的容器信息。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker ps -a<br></code></pre></td></tr></table></figure>

<figure class="highlight autoit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs autoit">[root<span class="hljs-symbol">@iZ2ze4hnl6pls28qt4w1ttZ</span> serInfo]<span class="hljs-meta"># docker ps -a</span><br>CONTAINER ID   IMAGE                COMMAND    CREATED         STATUS                     PORTS     NAMES<br>cb2146386e71   hello-world:latest   <span class="hljs-string">&quot;/hello&quot;</span>   <span class="hljs-number">3</span> minutes ago   Exited (<span class="hljs-number">0</span>) <span class="hljs-number">3</span> minutes ago             helloworld<br></code></pre></td></tr></table></figure>

<p>删除镜像。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docekr remove helloworld<br></code></pre></td></tr></table></figure>

<p>镜像源问题解决了，构建 Docker 镜像的报错问题还没有进展，检查下 Dockerfile 文件内容。</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 基础镜像</span><br><span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">8</span><br><span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br><span class="hljs-keyword">ADD</span><span class="language-bash"> target/hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">&quot;java&quot;</span>,<span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;/app.jar&quot;</span>]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br><span class="hljs-keyword">EXPOSE</span>  <span class="hljs-number">8080</span><br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1831926133062430721">5 个提升你 Dockerfile 水平 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<p>Dockerfile 有挺多技巧：</p>
<ol>
<li>使用 alpine 的镜像，而不是默认的 linux 镜像，可以极大减小镜像体积，比如 node:18-alpine3.14 这种</li>
<li>使用多阶段构建，比如一个阶段来执行 build，一个阶段把文件复制过去，跑起服务来，最后只保留最后一个阶段的镜像。这样使镜像内只保留运行需要的文件以及 dependencies。</li>
<li>使用 ARG 增加构建灵活性，ARG 可以在 docker build 时通过 –build-arg xxx=yyy 传入，在 dockerfile 中生效，可以使构建过程更灵活。如果是想定义运行时可以访问的变量，可以通过 ENV 定义环境变量，值使用 ARG 传入。</li>
<li>CMD 和 ENTRYPOINT 都可以指定容器跑起来之后运行的命令，CMD 可以被覆盖，而 ENTRYPOINT 不可以，两者结合使用可以实现参数默认值的功能。</li>
<li>ADD 和 COPY 都可以复制文件到容器内，但是 ADD 处理 tar.gz 的时候，还会做一下解压。</li>
</ol>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/2372154">Docker 镜像构建知识：Dockerfile 命令详解-腾讯云开发者社区-腾讯云 (tencent.com)</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 基础镜像</span><br>FROM scratch<br><span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br>ADD hello-0.0.1-SNAPSHOT.jar app.jar<br><span class="hljs-comment"># 容器启动执行命令</span><br>ENTRYPOINT [<span class="hljs-string">&quot;java&quot;</span>,<span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;/app.jar&quot;</span>]<br><span class="hljs-comment"># 对外暴露的端口号</span><br>EXPOSE  8080<br></code></pre></td></tr></table></figure>

<p>构建成功了对吧。</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs ruby">[root<span class="hljs-variable">@iZ2ze4hnl6pls28qt4w1ttZ</span> serInfo]<span class="hljs-comment"># docker build -t hello-app .</span><br>[+] <span class="hljs-title class_">Building</span> <span class="hljs-number">0</span>.4s (<span class="hljs-number">5</span>/<span class="hljs-number">5</span>) <span class="hljs-variable constant_">FINISHED</span>   <span class="hljs-symbol">docker:</span>default<br> =&gt; [internal] load build definition from <span class="hljs-title class_">Dockerfile</span>   			    <span class="hljs-number">0</span>.0s<br> =&gt; =&gt; transferring <span class="hljs-symbol">dockerfile:</span> 313B                         		<span class="hljs-number">0</span>.0s<br> =&gt; [internal] load .dockerignore                                    <span class="hljs-number">0</span>.0s<br> =&gt; =&gt; transferring <span class="hljs-symbol">context:</span> 2B                                      <span class="hljs-number">0</span>.0s<br> =&gt; [internal] load build context                                    <span class="hljs-number">0</span>.2s<br> =&gt; =&gt; transferring <span class="hljs-symbol">context:</span> <span class="hljs-number">17</span>.65MB                                 <span class="hljs-number">0</span>.2s<br> =&gt; [<span class="hljs-number">1</span>/<span class="hljs-number">1</span>] <span class="hljs-variable constant_">ADD</span> hello-<span class="hljs-number">0.0</span>.<span class="hljs-number">1</span>-<span class="hljs-variable constant_">SNAPSHOT</span>.jar app.jar                       <span class="hljs-number">0</span>.0s<br> =&gt; exporting to image                                               <span class="hljs-number">0</span>.1s<br> =&gt; =&gt; exporting layers                                              <span class="hljs-number">0</span>.1s<br> =&gt; =&gt; writing image <span class="hljs-symbol">sha256:</span>19baea50ee1023afb4c6926836a32e3816a315de477db0fcf3d164e25b1ed5b2<br></code></pre></td></tr></table></figure>

<p>镜像运行失败了。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -p 8080:8080 --name helloapp hello-app:latest<br></code></pre></td></tr></table></figure>

<figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs n1ql">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker run -p 8080:8080 --name helloapp hello-app:latest<br>docker: Error response from daemon: failed to <span class="hljs-keyword">create</span> task <span class="hljs-keyword">for</span> container: failed <span class="hljs-keyword">to</span> <span class="hljs-keyword">create</span> shim task: OCI runtime <span class="hljs-keyword">create</span> failed: runc <span class="hljs-keyword">create</span> failed: unable <span class="hljs-keyword">to</span> <span class="hljs-keyword">start</span> container process: exec: <span class="hljs-string">&quot;java&quot;</span>: executable file <span class="hljs-keyword">not</span> found <span class="hljs-keyword">in</span> $<span class="hljs-keyword">PATH</span>: <span class="hljs-keyword">unknown</span>.<br></code></pre></td></tr></table></figure>

<p>缺少 Java 环境。</p>
<p>停止容器，删除容器。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker ps -a</span><br>CONTAINER ID   IMAGE              COMMAND                CREATED          STATUS    PORTS                                       NAMES<br>eefe17b7f1e2   hello-app          <span class="hljs-string">&quot;java -jar /app.jar&quot;</span>   2 minutes ago    Created   8080/tcp                                    heuristic_jackson<br>da15a61a2596   hello-app:latest   <span class="hljs-string">&quot;java -jar /app.jar&quot;</span>   12 minutes ago   Created   0.0.0.0:8080-&gt;8080/tcp, :::8080-&gt;8080/tcp   helloapp<br></code></pre></td></tr></table></figure>

<figure class="highlight autoit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs autoit">[root<span class="hljs-symbol">@iZ2ze4hnl6pls28qt4w1ttZ</span> serInfo]<span class="hljs-meta"># docker remove eefe17b7f1e2</span><br>eefe17b7f1e2<br></code></pre></td></tr></table></figure>

<p>删除镜像。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker rmi 19baea50ee10</span><br>Untagged: hello-app:latest<br></code></pre></td></tr></table></figure>

<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs crmsh">[root@iZ2ze4hnl6pls28qt4w1ttZ ser<span class="hljs-literal">Inf</span>o]<span class="hljs-comment"># docker images</span><br>REPOSITORY    <span class="hljs-keyword">TAG</span>       <span class="hljs-title">IMAGE</span> ID       CREATED       SIZE<br>hello-world   latest    feb5d9fea6a5   <span class="hljs-number">3</span> years ago   <span class="hljs-number">13.3</span>kB<br></code></pre></td></tr></table></figure>

<p>重新构建镜像。</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 基础镜像</span><br><span class="hljs-keyword">FROM</span> scratch<br><span class="hljs-comment"># 作者信息</span><br><span class="hljs-keyword">MAINTAINER</span>  memory<br><span class="hljs-comment"># 安装jdk</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update &amp;&amp; apt-get install -y openjdk-8-jdk</span><br><span class="hljs-comment"># 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br><span class="hljs-keyword">ADD</span><span class="language-bash"> hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">&quot;java&quot;</span>,<span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;/app.jar&quot;</span>]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br><span class="hljs-keyword">EXPOSE</span>  <span class="hljs-number">8080</span><br></code></pre></td></tr></table></figure>

<p>很显然这条命令又报错了。</p>
<figure class="highlight asciidoc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs asciidoc">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker build -t hello-app .<br>[+] Building 0.3s (4/5)<br><span class="hljs-code"> &gt; [1/2] RUN apt-get update &amp;&amp; apt-get install -y openjdk-8-jdk:</span><br><span class="hljs-section">0.215 runc run failed: unable to start container process: exec: &quot;/bin/sh&quot;: stat /bin/sh: no such file or directory</span><br><span class="hljs-section">------</span><br><span class="hljs-section">Dockerfile:6</span><br><span class="hljs-section">--------------------</span><br><span class="hljs-code">   4 |     MAINTAINER  memory</span><br><span class="hljs-code">   5 |     # 安装jdk</span><br><span class="hljs-code">   6 | &gt;&gt;&gt; RUN apt-get update &amp;&amp; apt-get install -y openjdk-8-jdk</span><br><span class="hljs-code">   7 |     # 复制主机jar包至镜像内，复制的目录需放置在 Dockerfile 文件同级目录下</span><br><span class="hljs-section">   8 |     ADD hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-section">--------------------</span><br>ERROR: failed to solve: process &quot;/bin/sh -c apt-get update &amp;&amp; apt-get install -y openjdk-8-jdk&quot; did not complete successfully: exit code: 1<br><br></code></pre></td></tr></table></figure>

<p>修改 Dockerfile 文件。</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 使用 CentOS 基础镜像</span><br><span class="hljs-keyword">FROM</span> centos:latest<br><span class="hljs-comment"># 作者信息</span><br><span class="hljs-keyword">MAINTAINER</span>  memory<br><span class="hljs-comment"># 安装必要的软件包</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> yum install -y java-1.8.0-openjdk-devel</span><br><span class="hljs-comment"># 设置工作目录</span><br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span><br><span class="hljs-comment"># 复制 JAR 文件到工作目录</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> hello-0.0.1-SNAPSHOT.jar app.jar</span><br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">&quot;java&quot;</span>, <span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;app.jar&quot;</span>]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span><br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.51cto.com/u_16213457/13009383">dockerfile 安装 java 环境_mob64ca12f66e6c 的技术博客_51CTO 博客</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.51cto.com/u_16213353/12311905">docker 容器配置 java 环境_mob64ca12dd8bce 的技术博客_51CTO 博客</a></p>
<p>又忙活了一个多小时许可证后台管理系统，只要着手搞这玩意儿时间就过得可快了，这会儿都快五点钟，该下班了。</p>
<p>再试试：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 使用 CentOS 基础镜像</span><br>FROM centos:latest<br>FROM openjdk:8-jdk-alpine<br><span class="hljs-comment"># 作者信息</span><br>MAINTAINER  memory<br><span class="hljs-comment"># 配置java环境变量</span><br>ENV JAVA_HOME /opt/jdk/jdk1.8.0_412<br>ENV CLASSPATH <span class="hljs-variable">$JAVA_HOME</span>/lib/dt.jar:<span class="hljs-variable">$JAVA_HOME</span>/lib/tools.jar<br>ENV PATH <span class="hljs-variable">$PATH</span>:<span class="hljs-variable">$JAVA_HOME</span>/bin<br><span class="hljs-comment"># 设置工作目录</span><br>WORKDIR /app<br><span class="hljs-comment"># 复制 JAR 文件到工作目录</span><br>COPY hello-0.0.1-SNAPSHOT.jar app.jar<br><span class="hljs-comment"># 容器启动执行命令</span><br><span class="hljs-comment">#ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]</span><br><span class="hljs-comment"># 对外暴露的端口号</span><br>EXPOSE 8080<br></code></pre></td></tr></table></figure>

<p>待解决问题：</p>
<figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs livecodeserver">unable <span class="hljs-built_in">to</span> <span class="hljs-built_in">start</span> container <span class="hljs-built_in">process</span>: exec: <span class="hljs-string">&quot;java&quot;</span>: executable <span class="hljs-built_in">file</span> <span class="hljs-keyword">not</span> found <span class="hljs-keyword">in</span> $PATH: unknown.<br></code></pre></td></tr></table></figure>

<blockquote>
<p>2025 年 2 月 6 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/lnh1998/article/details/131293754">exec failed: unable to start container process: exec: “ip“: executable file not found in $PATH_oci runtime exec failed: exec failed: unable to st-CSDN 博客</a></p>
<p>问题报错：</p>
<figure class="highlight mel"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mel">OCI runtime <span class="hljs-keyword">exec</span> failed: <span class="hljs-keyword">exec</span> failed: unable to start <span class="hljs-keyword">container</span> process: <span class="hljs-keyword">exec</span>: <span class="hljs-string">&quot;ip&quot;</span>: executable <span class="hljs-keyword">file</span> not found <span class="hljs-keyword">in</span> $PATH: unknown<br></code></pre></td></tr></table></figure>

<p>报错原因：因为该容器的镜像时精简版，内部缺少 iproute2 导致无法使用 ip 命令</p>
<p>解决方式：</p>
<p>进入容器</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it 容器名 /bin/bash<br></code></pre></td></tr></table></figure>

<p>进入后：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 更新apt</span><br>apt-get update<br><br><span class="hljs-comment"># 安装iproute2</span><br>agt install -y iproute2<br><br><span class="hljs-comment"># 安装完以后退出exit</span><br>docker <span class="hljs-built_in">exec</span> -it 容器名 ip addr<br></code></pre></td></tr></table></figure>

<p>这段不太实用，我的问题不在于容器启动后报错，而是容器根本没有启动成功，没法进入一个不在运行过程中的容器。</p>
<p>镜像 Dockerfile 的问题。</p>
<p><a target="_blank" rel="noopener" href="https://blog.huochengrm.cn/ask/13337.html">如何顺利进入 Docker 容器内部？-HCRM 博客 (huochengrm.cn)</a></p>
<blockquote>
<p>2025 年 2 月 10 日</p>
</blockquote>
<p>本地虚拟机 Docker 安装完成，不过还要修改 Docker Hub 阿里云镜像源。</p>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1790498">Docker 系列(3) —— 切换 Docker 镜像源-腾讯云开发者社区-腾讯云 (tencent.com)</a></p>
<p>这样的配置方法相比上面所提供的，也许会更加全面一些。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">vi /etc/docker/daemon.json<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs bash">&#123;<br>  <span class="hljs-string">&quot;registry-mirrors&quot;</span>: [<br>    <span class="hljs-string">&quot;https://7bezldxe.mirror.aliyuncs.com/&quot;</span>,<br>    <span class="hljs-string">&quot;https://docker.mirrors.ustc.edu.cn/&quot;</span>,<br>    <span class="hljs-string">&quot;https://hub-mirror.c.163.com&quot;</span>,<br>    <span class="hljs-string">&quot;https://registry.docker-cn.com&quot;</span><br>  ],<br>  <span class="hljs-string">&quot;insecure-registries&quot;</span>: [],<br>  <span class="hljs-string">&quot;debug&quot;</span>: <span class="hljs-literal">false</span>,<br>  <span class="hljs-string">&quot;experimental&quot;</span>: <span class="hljs-literal">false</span>,<br>  <span class="hljs-string">&quot;features&quot;</span>: &#123;<br>    <span class="hljs-string">&quot;buildkit&quot;</span>: <span class="hljs-literal">true</span><br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl start docker.service<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl status docker.service<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull hello-world<br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/YUEAwb/article/details/138108576">Docker 基础命令_docker 查看镜像-CSDN 博客</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker info<br></code></pre></td></tr></table></figure>

<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs awk">Registry Mirrors:<br> https:<span class="hljs-regexp">//</span><span class="hljs-number">7</span>bezldxe.mirror.aliyuncs.com/<br></code></pre></td></tr></table></figure>

<p>显然更新配置后再次拉取镜像没有生效，镜像源还是没有修改完成。</p>
<p>明天见吧，我的朋友。</p>
<h2 id="Dockerfile-部署"><a href="#Dockerfile-部署" class="headerlink" title="Dockerfile 部署"></a>Dockerfile 部署</h2><blockquote>
<p>2025 年 2 月 6 日</p>
</blockquote>
<p>启动成功！</p>
<p><img src="http://blog.memory-life.xyz/Snipaste_2025-02-06_09-35-22.png" alt="Snipaste_2025-02-06_09-35-22"></p>
<p>删除容器，删除镜像，重新构建镜像再运行容器。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker ps -a<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker remove helloapp<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker images<br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker rmi hello-app<br></code></pre></td></tr></table></figure>

<p>更新 Dockerfile 文件，选择使用官方 JDK 镜像。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 使用 CentOS 基础镜像</span><br>FROM centos:latest<br><span class="hljs-comment"># 使用官方 JDK 镜像</span><br>FROM openjdk:8-jdk-alpine<br><span class="hljs-comment"># 作者信息</span><br>MAINTAINER  memory<br><span class="hljs-comment"># 查看 JAVA 版本</span><br>RUN java -version<br><span class="hljs-comment"># 设置工作目录</span><br>WORKDIR /app<br><span class="hljs-comment"># 复制 JAR 文件到工作目录</span><br>COPY hello-0.0.1-SNAPSHOT.jar app.jar<br><span class="hljs-comment"># 容器启动执行命令</span><br>ENTRYPOINT [<span class="hljs-string">&quot;java&quot;</span>, <span class="hljs-string">&quot;-jar&quot;</span>, <span class="hljs-string">&quot;app.jar&quot;</span>]<br><span class="hljs-comment"># 对外暴露的端口号</span><br>EXPOSE 8080<br></code></pre></td></tr></table></figure>

<p>把 jar 包和编辑完善的 Dockerfile 文件放在同级目录下。</p>
<p>构建镜像。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker build -t hello-app .<br></code></pre></td></tr></table></figure>

<p><img src="http://blog.memory-life.xyz/image-20250206095024612.png" alt="image-20250206095024612"></p>
<p>创建并运行容器。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -p 8080:8080 --name helloapp hello-app:latest<br></code></pre></td></tr></table></figure>

<p><img src="http://blog.memory-life.xyz/Snipaste_2025-02-06_09-35-22.png" alt="Snipaste_2025-02-06_09-35-22"></p>
<p>可以说这是今年的开门红，初步掌握一门新技术：docker 容器部署。</p>
<p>进入正在运行中的容器并以命令行交互。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it helloapp /bin/bash<br></code></pre></td></tr></table></figure>

<p>或者：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it helloapp /bin/sh<br></code></pre></td></tr></table></figure>

<p>列表查看。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">ls</span><br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker exec -it helloapp /bin/sh</span><br>/app <span class="hljs-comment"># ll</span><br>/bin/sh: ll: not found<br>/app <span class="hljs-comment"># ls</span><br>app.jar<br></code></pre></td></tr></table></figure>

<p>退出容器。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">exit</span><br></code></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">/app <span class="hljs-comment"># exit</span><br>[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment">#</span><br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/u013250861/article/details/126924886">shell：bash【Bourne-Again SHell】_bourne again shell-CSDN 博客</a></p>
<p>[<a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_34326179/article/details/93089023">Linux] Bourne Again Shell-CSDN 博客</a></p>
<p>正巧看到这篇文章，写得很全很详细，点开主页一看竟然是一位年均输出大几百篇技术文章的大佬，不过一九年停更了。</p>
<p>快到饭点了，接下来安排的任务是尝试 docker 部署后台管理项目，以及 docker 远程部署。</p>
<p>同样的步骤，编写 Dockerfile 文件，构建镜像文件，启动并运行容器，接下来就应该开放阿里云服务器端口号了。</p>
<p>倒是接口文档可以正常访问，不过连接数据库失败了。</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs awk">http:<span class="hljs-regexp">//</span><span class="hljs-number">8.141</span>.<span class="hljs-number">90.145</span>:<span class="hljs-number">8082</span><span class="hljs-regexp">/backend-server/</span>doc.html<br></code></pre></td></tr></table></figure>

<p>获取 docker 容器环境变量。</p>
<p>着手测试。</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs awk">http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">8080</span><span class="hljs-regexp">/api/</span>test<br></code></pre></td></tr></table></figure>

<p>携带环境变量，启动项目。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -p 8080:8080 --name helloapp -e APP_NAME=<span class="hljs-string">&quot;My Awesome App&quot;</span> -e APP_PORT=8080 hello-app:latest<br></code></pre></td></tr></table></figure>

<p>可以这么干，那就更新下接口。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 测试接口</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@GetMapping(&quot;/test&quot;)</span><br><span class="hljs-keyword">public</span> String <span class="hljs-title function_">test</span><span class="hljs-params">()</span> &#123;<br>    System.out.println(<span class="hljs-string">&quot;Hello World&quot;</span>);<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Hello World&quot;</span>;<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 测试接口2</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@GetMapping(&quot;/test2&quot;)</span><br><span class="hljs-keyword">public</span> String <span class="hljs-title function_">test2</span><span class="hljs-params">()</span> &#123;<br>    Map&lt;String, String&gt; getenv = System.getenv();<br>    System.out.println(getenv);<br>    <span class="hljs-type">String</span> <span class="hljs-variable">appName</span> <span class="hljs-operator">=</span> System.getenv(<span class="hljs-string">&quot;APP_NAME&quot;</span>);<br>    System.out.println(appName);<br>    <span class="hljs-type">String</span> <span class="hljs-variable">appPort</span> <span class="hljs-operator">=</span> System.getenv(<span class="hljs-string">&quot;APP_PORT&quot;</span>);<br>    System.out.println(appPort);<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Hello World&quot;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>出问题了。</p>
<p>怎么访问不到接口呢。</p>
<p>本地测试没问题啊，docker 部署服务启动也是没问题的，难道是打包更新后的代码出问题了吗，再试试。</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs awk">http:<span class="hljs-regexp">//</span><span class="hljs-number">8.141</span>.<span class="hljs-number">90.145</span>:<span class="hljs-number">8080</span><span class="hljs-regexp">/api/</span>test2<br></code></pre></td></tr></table></figure>

<p>果然是这样，成功了。</p>
<p><img src="http://blog.memory-life.xyz/image-20250206153451255.png" alt="image-20250206153451255"></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]<span class="hljs-comment"># docker run -p 8080:8080 --name helloapp -e APP_NAME=&quot;My Awesome App&quot; -e APP_PORT=8080 hello-app:latest</span><br><br>  .   ____          _            __ _ _<br> /\\ / ___<span class="hljs-string">&#x27;_ __ _ _(_)_ __  __ _ \ \ \ \</span><br><span class="hljs-string">( ( )\___ | &#x27;</span>_ | <span class="hljs-string">&#x27;_| | &#x27;</span>_ \/ _` | \ \ \ \<br> \\/  ___)| |_)| | | | | || (_| |  ) ) ) )<br>  <span class="hljs-string">&#x27;  |____| .__|_| |_|_| |_\__, | / / / /</span><br><span class="hljs-string"> =========|_|==============|___/=/_/_/_/</span><br><span class="hljs-string"> :: Spring Boot ::                (v2.7.7)</span><br><span class="hljs-string"></span><br><span class="hljs-string">2025-02-06 07:30:58.477  INFO 1 --- [           main] org.tellhow.info.hello.HelloApplication  : Starting HelloApplication v0.0.1-SNAPSHOT using Java 1.8.0_212 on 9ed306a10b37 with PID 1 (/app/app.jar started by root in /app)</span><br><span class="hljs-string">2025-02-06 07:30:58.484  INFO 1 --- [           main] org.tellhow.info.hello.HelloApplication  : The following 1 profile is active: &quot;dev&quot;</span><br><span class="hljs-string">2025-02-06 07:30:59.972  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)</span><br><span class="hljs-string">2025-02-06 07:30:59.988  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]</span><br><span class="hljs-string">2025-02-06 07:30:59.988  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.70]</span><br><span class="hljs-string">2025-02-06 07:31:00.135  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext</span><br><span class="hljs-string">2025-02-06 07:31:00.135  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1499 ms</span><br><span class="hljs-string">2025-02-06 07:31:00.679  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path &#x27;</span><span class="hljs-string">&#x27;</span><br><span class="hljs-string">2025-02-06 07:31:00.694  INFO 1 --- [           main] org.tellhow.info.hello.HelloApplication  : Started HelloApplication in 2.989 seconds (JVM running for 3.58)</span><br><span class="hljs-string">Hello world!</span><br><span class="hljs-string">2025-02-06 07:31:06.094  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet &#x27;</span>dispatcherServlet<span class="hljs-string">&#x27;</span><br><span class="hljs-string">2025-02-06 07:31:06.095  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet &#x27;</span>dispatcherServlet<span class="hljs-string">&#x27;</span><br><span class="hljs-string">2025-02-06 07:31:06.096  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms</span><br><span class="hljs-string">Hello World</span><br><span class="hljs-string">&#123;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin, HOSTNAME=9ed306a10b37, JAVA_ALPINE_VERSION=8.212.04-r0, LD_LIBRARY_PATH=/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64:/usr/lib/jvm/java-1.8-openjdk/jre/../lib/amd64, JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk, APP_NAME=My Awesome App, JAVA_VERSION=8u212, LANG=C.UTF-8, APP_PORT=8080, HOME=/root&#125;</span><br><span class="hljs-string">My Awesome App</span><br><span class="hljs-string">8080</span><br></code></pre></td></tr></table></figure>

<p>嘿嘿哈哈，看来通过 Java 代码获取封装在 Docker 容器环境变量中的服务器硬件信息是可取的，开启下一步修改。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java">Map&lt;String, String&gt; getenv = System.getenv();<br>System.out.println(getenv);<br><span class="hljs-type">String</span> <span class="hljs-variable">appName</span> <span class="hljs-operator">=</span> System.getenv(<span class="hljs-string">&quot;APP_NAME&quot;</span>);<br>System.out.println(appName);<br><span class="hljs-type">String</span> <span class="hljs-variable">appPort</span> <span class="hljs-operator">=</span> System.getenv(<span class="hljs-string">&quot;APP_PORT&quot;</span>);<br>System.out.println(appPort);<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs JAVA"><span class="hljs-comment">// 获取现场服务器硬件信息</span><br>           <span class="hljs-comment">// 获取容器环境变量</span><br>           <span class="hljs-type">LicenseCheckModel</span> <span class="hljs-variable">hardwareInfo</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LicenseCheckModel</span>();<br>           <span class="hljs-type">String</span> <span class="hljs-variable">ipAddressEnv</span> <span class="hljs-operator">=</span> System.getenv(LicenseConstant.IP_ADDRESS_ENV);<br>           <span class="hljs-type">String</span> <span class="hljs-variable">MacAddressEnv</span> <span class="hljs-operator">=</span> System.getenv(LicenseConstant.MAC_ADDRESS_ENV);<br>           <span class="hljs-type">String</span> <span class="hljs-variable">CpuSerialEnv</span> <span class="hljs-operator">=</span> System.getenv(LicenseConstant.CPU_SERIAL_ENV);<br>           <span class="hljs-type">String</span> <span class="hljs-variable">MainBoardSerialEnv</span> <span class="hljs-operator">=</span> System.getenv(LicenseConstant.MAINBOARD_SERIAL_ENV);<br>           <span class="hljs-keyword">if</span> (ObjectUtils.isNotEmpty(ipAddressEnv)) &#123;<br>               hardwareInfo.setIpAddress(Lists.newArrayList(ipAddressEnv.split(<span class="hljs-string">&quot;,&quot;</span>)));<br>           &#125;<br>           <span class="hljs-keyword">if</span> (ObjectUtils.isNotEmpty(MacAddressEnv)) &#123;<br>               hardwareInfo.setMacAddress(Lists.newArrayList(MacAddressEnv.split(<span class="hljs-string">&quot;,&quot;</span>)));<br>           &#125;<br>           <span class="hljs-keyword">if</span> (ObjectUtils.isNotEmpty(CpuSerialEnv)) &#123;<br>               hardwareInfo.setCpuSerial(CpuSerialEnv);<br>           &#125;<br>           <span class="hljs-keyword">if</span> (ObjectUtils.isNotEmpty(MainBoardSerialEnv)) &#123;<br>               hardwareInfo.setMainBoardSerial(MainBoardSerialEnv);<br>           &#125;<br>           <span class="hljs-comment">// 现场服务器硬件信息</span><br>           <span class="hljs-keyword">if</span> (ObjectUtils.isEmpty(hardwareInfo)) &#123;<br>               log.error(<span class="hljs-string">&quot;请输入现场服务器硬件信息！&quot;</span>);<br>               <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">CommonException</span>(<span class="hljs-number">401</span>, <span class="hljs-string">&quot;请输入现场服务器硬件信息！&quot;</span>);<br>           &#125;<br>           <span class="hljs-comment">// 设置现场服务器硬件信息</span><br>           HardwareInfoContext.setHardwareInfo(hardwareInfo);<br></code></pre></td></tr></table></figure>

<p>接下来的内容，就记录在别的栏目了，纯业务，与技术无关。</p>
<blockquote>
<p>2025 年 2 月 7 日</p>
</blockquote>
<p>docker 远程部署。</p>
<p><a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1776245631845789697#heading-4">IDEA+Docker 远程部署 Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<p><img src="http://blog.memory-life.xyz/image-20250207150825887.png" alt="image-20250207150825887"></p>
<p>两天了，刚刚看到这个连接 Docker 失败的提示。</p>
<p>算了，前天的记录内容就网上翻找吧，在此就不做复杂的排版了。</p>
<figure class="highlight mercury"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mercury">Only key-pair ssh auth <span class="hljs-keyword">type</span> <span class="hljs-keyword">is</span> supported for docker connections.<br></code></pre></td></tr></table></figure>

<p>远程部署成功！</p>
<p><img src="http://blog.memory-life.xyz/image-20250207155252693.png" alt="image-20250207155252693"></p>
<blockquote>
<p>2025 年 2 月 8 日</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://www.codefather.cn/post/1776245631845789697#heading-2">IDEA+Docker 远程部署 Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)</a></p>
<p>[在 IDEA 中通过密钥认证的方式使用 SSH 连接远程 Linux 服务器_idea ssh 密码登录-CSDN 博客](</p>
<h1 id="1-初识-Docker"><a href="#1-初识-Docker" class="headerlink" title="1.初识 Docker"></a>1.初识 Docker</h1><h2 id="1-1-什么是-Docker"><a href="#1-1-什么是-Docker" class="headerlink" title="1.1.什么是 Docker"></a>1.1.什么是 Docker</h2><p>微服务虽然具备各种各样的优势，但服务的拆分通用给部署带来了很大的麻烦。</p>
<ul>
<li>分布式系统中，依赖的组件非常多，不同组件之间部署时往往会产生一些冲突。</li>
<li>在数百上千台服务中重复部署，环境不一定一致，会遇到各种问题</li>
</ul>
<h3 id="1-1-1-应用部署的环境问题"><a href="#1-1-1-应用部署的环境问题" class="headerlink" title="1.1.1.应用部署的环境问题"></a>1.1.1.应用部署的环境问题</h3><p>大型项目组件较多，运行环境也较为复杂，部署时会碰到一些问题：</p>
<ul>
<li><p>依赖关系复杂，容易出现兼容性问题</p>
</li>
<li><p>开发、测试、生产环境有差异</p>
</li>
</ul>
<p><img src="http://blog.memory-life.xyz/image-20210731141907366.png" alt="image-20210731141907366"></p>
<p>例如一个项目中，部署时需要依赖于 node.js、Redis、RabbitMQ、MySQL 等，这些服务部署时所需要的函数库、依赖项各不相同，甚至会有冲突。给部署带来了极大的困难。</p>
<h3 id="1-1-2-Docker-解决依赖兼容问题"><a href="#1-1-2-Docker-解决依赖兼容问题" class="headerlink" title="1.1.2.Docker 解决依赖兼容问题"></a>1.1.2.Docker 解决依赖兼容问题</h3><p>而 Docker 确巧妙的解决了这些问题，Docker 是如何实现的呢？</p>
<p>Docker 为了解决依赖的兼容问题的，采用了两个手段：</p>
<ul>
<li><p>将应用的 Libs（函数库）、Deps（依赖）、配置与应用一起打包</p>
</li>
<li><p>将每个应用放到一个隔离<strong>容器</strong>去运行，避免互相干扰</p>
</li>
</ul>
<p><img src="http://blog.memory-life.xyz/image-20210731142219735.png" alt="image-20210731142219735"></p>
<p>这样打包好的应用包中，既包含应用本身，也保护应用所需要的 Libs、Deps，无需再操作系统上安装这些，自然就不存在不同应用之间的兼容问题了。</p>
<p>虽然解决了不同应用的兼容问题，但是开发、测试等环境会存在差异，操作系统版本也会有差异，怎么解决这些问题呢？</p>
<h3 id="1-1-3-Docker-解决操作系统环境差异"><a href="#1-1-3-Docker-解决操作系统环境差异" class="headerlink" title="1.1.3.Docker 解决操作系统环境差异"></a>1.1.3.Docker 解决操作系统环境差异</h3><p>要解决不同操作系统环境差异问题，必须先了解操作系统结构。以一个 Ubuntu 操作系统为例，结构如下：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731143401460.png" alt="image-20210731143401460"></p>
<p>结构包括：</p>
<ul>
<li>计算机硬件：例如 CPU、内存、磁盘等</li>
<li>系统内核：所有 Linux 发行版的内核都是 Linux，例如 CentOS、Ubuntu、Fedora 等。内核可以与计算机硬件交互，对外提供<strong>内核指令</strong>，用于操作计算机硬件。</li>
<li>系统应用：操作系统本身提供的应用、函数库。这些函数库是对内核指令的封装，使用更加方便。</li>
</ul>
<p>应用于计算机交互的流程如下：</p>
<p>1）应用调用操作系统应用（函数库），实现各种功能</p>
<p>2）系统函数库是对内核指令集的封装，会调用内核指令</p>
<p>3）内核指令操作计算机硬件</p>
<p>Ubuntu 和 CentOSpringBoot 都是基于 Linux 内核，无非是系统应用不同，提供的函数库有差异：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731144304990.png" alt="image-20210731144304990"></p>
<p>此时，如果将一个 Ubuntu 版本的 MySQL 应用安装到 CentOS 系统，MySQL 在调用 Ubuntu 函数库时，会发现找不到或者不匹配，就会报错了：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731144458680.png" alt="image-20210731144458680"></p>
<p>Docker 如何解决不同系统环境的问题？</p>
<ul>
<li>Docker 将用户程序与所需要调用的系统(比如 Ubuntu)函数库一起打包</li>
<li>Docker 运行到不同操作系统时，直接基于打包的函数库，借助于操作系统的 Linux 内核来运行</li>
</ul>
<p>如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731144820638.png" alt="image-20210731144820638"></p>
<h3 id="1-1-4-小结"><a href="#1-1-4-小结" class="headerlink" title="1.1.4.小结"></a>1.1.4.小结</h3><p>Docker 如何解决大型项目依赖关系复杂，不同组件依赖的兼容性问题？</p>
<ul>
<li>Docker 允许开发中将应用、依赖、函数库、配置一起<strong>打包</strong>，形成可移植镜像</li>
<li>Docker 应用运行在容器中，使用沙箱机制，相互<strong>隔离</strong></li>
</ul>
<p>Docker 如何解决开发、测试、生产环境有差异的问题？</p>
<ul>
<li>Docker 镜像中包含完整运行环境，包括系统函数库，仅依赖系统的 Linux 内核，因此可以在任意 Linux 操作系统上运行</li>
</ul>
<p>Docker 是一个快速交付应用、运行应用的技术，具备下列优势：</p>
<ul>
<li>可以将程序及其依赖、运行环境一起打包为一个镜像，可以迁移到任意 Linux 操作系统</li>
<li>运行时利用沙箱机制形成隔离容器，各个应用互不干扰</li>
<li>启动、移除都可以通过一行命令完成，方便快捷</li>
</ul>
<h2 id="1-2-Docker-和虚拟机的区别"><a href="#1-2-Docker-和虚拟机的区别" class="headerlink" title="1.2.Docker 和虚拟机的区别"></a>1.2.Docker 和虚拟机的区别</h2><p>Docker 可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机，也能在一个操作系统中，运行另外一个操作系统，保护系统中的任何应用。</p>
<p>两者有什么差异呢？</p>
<p><strong>虚拟机</strong>（virtual machine）是在操作系统中<strong>模拟</strong>硬件设备，然后运行另一个操作系统，比如在 Windows 系统里面运行 Ubuntu 系统，这样就可以运行任意的 Ubuntu 应用了。</p>
<p><strong>Docker</strong>仅仅是封装函数库，并没有模拟完整的操作系统，如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731145914960.png" alt="image-20210731145914960"></p>
<p>对比来看：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731152243765.png" alt="image-20210731152243765"></p>
<p>小结：</p>
<p>Docker 和虚拟机的差异：</p>
<ul>
<li><p>docker 是一个系统进程；虚拟机是在操作系统中的操作系统</p>
</li>
<li><p>docker 体积小、启动速度快、性能好；虚拟机体积大、启动速度慢、性能一般</p>
</li>
</ul>
<h2 id="1-3-Docker-架构"><a href="#1-3-Docker-架构" class="headerlink" title="1.3.Docker 架构"></a>1.3.Docker 架构</h2><h3 id="1-3-1-镜像和容器"><a href="#1-3-1-镜像和容器" class="headerlink" title="1.3.1.镜像和容器"></a>1.3.1.镜像和容器</h3><p>Docker 中有几个重要的概念：</p>
<p><strong>镜像（Image）</strong>：Docker 将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起，称为镜像。</p>
<p><strong>容器（Container）</strong>：镜像中的应用程序运行后形成的进程就是<strong>容器</strong>，只是 Docker 会给容器进程做隔离，对外不可见。</p>
<p>一切应用最终都是代码组成，都是硬盘中的一个个的字节形成的<strong>文件</strong>。只有运行时，才会加载到内存，形成进程。</p>
<p>而<strong>镜像</strong>，就是把一个应用在硬盘上的文件、及其运行环境、部分系统函数库文件一起打包形成的文件包。这个文件包是只读的。</p>
<p><strong>容器</strong>呢，就是将这些文件中编写的程序、函数加载到内存中允许，形成进程，只不过要隔离起来。因此一个镜像可以启动多次，形成多个容器进程。</p>
<p><img src="http://blog.memory-life.xyz/image-20210731153059464.png" alt="image-20210731153059464"></p>
<p>例如你下载了一个 QQ，如果我们将 QQ 在磁盘上的运行<strong>文件</strong>及其运行的操作系统依赖打包，形成 QQ 镜像。然后你可以启动多次，双开、甚至三开 QQ，跟多个妹子聊天。</p>
<h3 id="1-3-2-DockerHub"><a href="#1-3-2-DockerHub" class="headerlink" title="1.3.2.DockerHub"></a>1.3.2.DockerHub</h3><p>开源应用程序非常多，打包这些应用往往是重复的劳动。为了避免这些重复劳动，人们就会将自己打包的应用镜像，例如 Redis、MySQL 镜像放到网络上，共享使用，就像 GitHub 的代码共享一样。</p>
<ul>
<li><p>DockerHub：DockerHub 是一个官方的 Docker 镜像的托管平台。这样的平台称为 Docker Registry。</p>
</li>
<li><p>国内也有类似于 DockerHub 的公开服务，比如 <a target="_blank" rel="noopener" href="https://c.163yun.com/hub">网易云镜像服务</a>、<a target="_blank" rel="noopener" href="https://cr.console.aliyun.com/">阿里云镜像库</a>等。</p>
</li>
</ul>
<p>我们一方面可以将自己的镜像共享到 DockerHub，另一方面也可以从 DockerHub 拉取镜像：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731153743354.png" alt="image-20210731153743354"></p>
<h3 id="1-3-3-Docker-架构"><a href="#1-3-3-Docker-架构" class="headerlink" title="1.3.3.Docker 架构"></a>1.3.3.Docker 架构</h3><p>我们要使用 Docker 来操作镜像、容器，就必须要安装 Docker。</p>
<p>Docker 是一个 CS 架构的程序，由两部分组成：</p>
<ul>
<li><p>服务端(server)：Docker 守护进程，负责处理 Docker 指令，管理镜像、容器等</p>
</li>
<li><p>客户端(client)：通过命令或 RestAPI 向 Docker 服务端发送指令。可以在本地或远程向服务端发送指令。</p>
</li>
</ul>
<p>如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731154257653.png" alt="image-20210731154257653"></p>
<h3 id="1-3-4-小结"><a href="#1-3-4-小结" class="headerlink" title="1.3.4.小结"></a>1.3.4.小结</h3><p>镜像：</p>
<ul>
<li>将应用程序及其依赖、环境、配置打包在一起</li>
</ul>
<p>容器：</p>
<ul>
<li>镜像运行起来就是容器，一个镜像可以运行多个容器</li>
</ul>
<p>Docker 结构：</p>
<ul>
<li><p>服务端：接收命令或远程请求，操作镜像或容器</p>
</li>
<li><p>客户端：发送命令或者请求到 Docker 服务端</p>
</li>
</ul>
<p>DockerHub：</p>
<ul>
<li>一个镜像托管的服务器，类似的还有阿里云镜像服务，统称为 DockerRegistry</li>
</ul>
<h2 id="1-4-安装-Docker"><a href="#1-4-安装-Docker" class="headerlink" title="1.4.安装 Docker"></a>1.4.安装 Docker</h2><p>企业部署一般都是采用 Linux 操作系统，而其中又数 CentOS 发行版占比最多，因此我们在 CentOS 下安装 Docker。参考课前资料中的文档：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731155002425.png" alt="image-20210731155002425"></p>
<h1 id="2-Docker-的基本操作"><a href="#2-Docker-的基本操作" class="headerlink" title="2.Docker 的基本操作"></a>2.Docker 的基本操作</h1><h2 id="2-1-镜像操作"><a href="#2-1-镜像操作" class="headerlink" title="2.1.镜像操作"></a>2.1.镜像操作</h2><h3 id="2-1-1-镜像名称"><a href="#2-1-1-镜像名称" class="headerlink" title="2.1.1.镜像名称"></a>2.1.1.镜像名称</h3><p>首先来看下镜像的名称组成：</p>
<ul>
<li>镜名称一般分两部分组成：[repository]:[tag]。</li>
<li>在没有指定 tag 时，默认是 latest，代表最新版本的镜像</li>
</ul>
<p>如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731155141362.png" alt="image-20210731155141362"></p>
<p>这里的 mysql 就是 repository，5.7 就是 tag，合一起就是镜像名称，代表 5.7 版本的 MySQL 镜像。</p>
<h3 id="2-1-2-镜像命令"><a href="#2-1-2-镜像命令" class="headerlink" title="2.1.2.镜像命令"></a>2.1.2.镜像命令</h3><p>常见的镜像操作命令如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731155649535.png" alt="image-20210731155649535"></p>
<h3 id="2-1-3-案例-1-拉取、查看镜像"><a href="#2-1-3-案例-1-拉取、查看镜像" class="headerlink" title="2.1.3.案例 1-拉取、查看镜像"></a>2.1.3.案例 1-拉取、查看镜像</h3><p>需求：从 DockerHub 中拉取一个 nginx 镜像并查看</p>
<p>1）首先去镜像仓库搜索 nginx 镜像，比如<a target="_blank" rel="noopener" href="https://hub.docker.com/">DockerHub</a>:</p>
<img src="http://blog.memory-life.xyz/image-20210731155844368.png" alt="image-20210731155844368" style="zoom:150%;" />

<p>2）根据查看到的镜像名称，拉取自己需要的镜像，通过命令：docker pull nginx</p>
<img src="http://blog.memory-life.xyz/image-20210731155856199.png" alt="image-20210731155856199" style="zoom:150%;" />

<p>3）通过命令：docker images 查看拉取到的镜像</p>
<p><img src="http://blog.memory-life.xyz/image-20210731155903037.png" alt="image-20210731155903037"></p>
<h3 id="2-1-4-案例-2-保存、导入镜像"><a href="#2-1-4-案例-2-保存、导入镜像" class="headerlink" title="2.1.4.案例 2-保存、导入镜像"></a>2.1.4.案例 2-保存、导入镜像</h3><p>需求：利用 docker save 将 nginx 镜像导出磁盘，然后再通过 load 加载回来</p>
<p>1）利用 docker xx –help 命令查看 docker save 和 docker load 的语法</p>
<p>例如，查看 save 命令用法，可以输入命令：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker save --<span class="hljs-built_in">help</span><br></code></pre></td></tr></table></figure>

<p>结果：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731161104732.png" alt="image-20210731161104732"></p>
<p>命令格式：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">docker save -o [保存的目标文件名称] [镜像名称]<br></code></pre></td></tr></table></figure>

<p>2）使用 docker save 导出镜像到磁盘</p>
<p>运行命令：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker save -o nginx.tar nginx:latest<br></code></pre></td></tr></table></figure>

<p>结果如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731161354344.png" alt="image-20210731161354344"></p>
<p>3）使用 docker load 加载镜像</p>
<p>先删除本地的 nginx 镜像：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker rmi nginx:latest<br></code></pre></td></tr></table></figure>

<p>然后运行命令，加载本地文件：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker load -i nginx.tar<br></code></pre></td></tr></table></figure>

<p>结果：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731161746245.png" alt="image-20210731161746245"></p>
<h3 id="2-1-5-练习"><a href="#2-1-5-练习" class="headerlink" title="2.1.5.练习"></a>2.1.5.练习</h3><p>需求：去 DockerHub 搜索并拉取一个 Redis 镜像</p>
<p>目标：</p>
<p>1）去 DockerHub 搜索 Redis 镜像</p>
<p>2）查看 Redis 镜像的名称和版本</p>
<p>3）利用 docker pull 命令拉取镜像</p>
<p>4）利用 docker save 命令将 redis:latest 打包为一个 redis.tar 包</p>
<p>5）利用 docker rmi 删除本地的 redis:latest</p>
<p>6）利用 docker load 重新加载 redis.tar 文件</p>
<h2 id="2-2-容器操作"><a href="#2-2-容器操作" class="headerlink" title="2.2.容器操作"></a>2.2.容器操作</h2><h3 id="2-2-1-容器相关命令"><a href="#2-2-1-容器相关命令" class="headerlink" title="2.2.1.容器相关命令"></a>2.2.1.容器相关命令</h3><p>容器操作的命令如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731161950495.png" alt="image-20210731161950495"></p>
<p>容器保护三个状态：</p>
<ul>
<li>运行：进程正常运行</li>
<li>暂停：进程暂停，CPU 不再运行，并不释放内存</li>
<li>停止：进程终止，回收进程占用的内存、CPU 等资源</li>
</ul>
<p>其中：</p>
<ul>
<li><p>docker run：创建并运行一个容器，处于运行状态</p>
</li>
<li><p>docker pause：让一个运行的容器暂停</p>
</li>
<li><p>docker unpause：让一个容器从暂停状态恢复运行</p>
</li>
<li><p>docker stop：停止一个运行的容器</p>
</li>
<li><p>docker start：让一个停止的容器再次运行</p>
</li>
<li><p>docker rm：删除一个容器</p>
</li>
</ul>
<h3 id="2-2-2-案例-创建并运行一个容器"><a href="#2-2-2-案例-创建并运行一个容器" class="headerlink" title="2.2.2.案例-创建并运行一个容器"></a>2.2.2.案例-创建并运行一个容器</h3><p>创建并运行 nginx 容器的命令：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run --name containerName -p 80:80 -d nginx<br></code></pre></td></tr></table></figure>

<p>命令解读：</p>
<ul>
<li>docker run ：创建并运行一个容器</li>
<li>–name : 给容器起一个名字，比如叫做 mn</li>
<li>-p ：将宿主机端口与容器端口映射，冒号左侧是宿主机端口，右侧是容器端口</li>
<li>-d：后台运行容器</li>
<li>nginx：镜像名称，例如 nginx</li>
</ul>
<p>这里的<code>-p</code>参数，是将容器端口映射到宿主机端口。</p>
<p>默认情况下，容器是隔离环境，我们直接访问宿主机的 80 端口，肯定访问不到容器中的 nginx。</p>
<p>现在，将容器的 80 与宿主机的 80 关联起来，当我们访问宿主机的 80 端口时，就会被映射到容器的 80，这样就能访问到 nginx 了：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731163255863.png" alt="image-20210731163255863"></p>
<h3 id="2-2-3-案例-进入容器，修改文件"><a href="#2-2-3-案例-进入容器，修改文件" class="headerlink" title="2.2.3.案例-进入容器，修改文件"></a>2.2.3.案例-进入容器，修改文件</h3><p><strong>需求</strong>：进入 Nginx 容器，修改 HTML 文件内容，添加“传智教育欢迎您”</p>
<p><strong>提示</strong>：进入容器要用到 docker exec 命令。</p>
<p><strong>步骤</strong>：</p>
<p>1）进入容器。进入我们刚刚创建的 nginx 容器的命令为：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker <span class="hljs-built_in">exec</span> -it mn bash<br></code></pre></td></tr></table></figure>

<p>命令解读：</p>
<ul>
<li><p>docker exec ：进入容器内部，执行一个命令</p>
</li>
<li><p>-it : 给当前进入的容器创建一个标准输入、输出终端，允许我们与容器交互</p>
</li>
<li><p>mn ：要进入的容器的名称</p>
</li>
<li><p>bash：进入容器后执行的命令，bash 是一个 linux 终端交互命令</p>
</li>
</ul>
<p>2）进入 nginx 的 HTML 所在目录 /usr/share/nginx/html</p>
<p>容器内部会模拟一个独立的 Linux 文件系统，看起来如同一个 linux 服务器一样：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731164159811.png" alt="image-20210731164159811"></p>
<p>nginx 的环境、配置、运行文件全部都在这个文件系统中，包括我们要修改的 html 文件。</p>
<p>查看 DockerHub 网站中的 nginx 页面，可以知道 nginx 的 html 目录位置在<code>/usr/share/nginx/html</code></p>
<p>我们执行命令，进入该目录：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh"><span class="hljs-built_in">cd</span> /usr/share/nginx/html<br></code></pre></td></tr></table></figure>

<p>查看目录下文件：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731164455818.png" alt="image-20210731164455818"></p>
<p>3）修改 index.html 的内容</p>
<p>容器内没有 vi 命令，无法直接修改，我们用下面的命令来修改：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">sed -i -e <span class="hljs-string">&#x27;s#Welcome to nginx#传智教育欢迎您#g&#x27;</span> -e <span class="hljs-string">&#x27;s#&lt;head&gt;#&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;#g&#x27;</span> index.html<br></code></pre></td></tr></table></figure>

<p>在浏览器访问自己的虚拟机地址，例如我的是：<a href="http://192.168.150.101，即可看到结果：">http://192.168.150.101，即可看到结果：</a></p>
<p><img src="http://blog.memory-life.xyz/image-20210731164717604.png" alt="image-20210731164717604"></p>
<h3 id="2-2-4-小结"><a href="#2-2-4-小结" class="headerlink" title="2.2.4.小结"></a>2.2.4.小结</h3><p>docker run 命令的常见参数有哪些？</p>
<ul>
<li>–name：指定容器名称</li>
<li>-p：指定端口映射</li>
<li>-d：让容器后台运行</li>
</ul>
<p>查看容器日志的命令：</p>
<ul>
<li>docker logs-</li>
<li>添加 -f 参数可以持续查看日志</li>
</ul>
<p>查看容器状态：</p>
<ul>
<li>docker ps</li>
<li>docker ps -a 查看所有容器，包括已经停止的</li>
</ul>
<h2 id="2-3-数据卷（容器数据管理）"><a href="#2-3-数据卷（容器数据管理）" class="headerlink" title="2.3.数据卷（容器数据管理）"></a>2.3.数据卷（容器数据管理）</h2><p>在之前的 nginx 案例中，修改 nginx 的 html 页面时，需要进入 nginx 内部。并且因为没有编辑器，修改文件也很麻烦。</p>
<p>这就是因为容器与数据（容器内文件）耦合带来的后果。</p>
<p><img src="http://blog.memory-life.xyz/image-20210731172440275.png" alt="image-20210731172440275"></p>
<p>要解决这个问题，必须将数据与容器解耦，这就要用到数据卷了。</p>
<h3 id="2-3-1-什么是数据卷"><a href="#2-3-1-什么是数据卷" class="headerlink" title="2.3.1.什么是数据卷"></a>2.3.1.什么是数据卷</h3><p><strong>数据卷（volume）</strong>是一个虚拟目录，指向宿主机文件系统中的某个目录。</p>
<p><img src="http://blog.memory-life.xyz/image-20210731173541846.png" alt="image-20210731173541846"></p>
<p>一旦完成数据卷挂载，对容器的一切操作都会作用在数据卷对应的宿主机目录了。</p>
<p>这样，我们操作宿主机的/var/lib/docker/volumes/html 目录，就等于操作容器内的/usr/share/nginx/html 目录了</p>
<h3 id="2-3-2-数据集操作命令"><a href="#2-3-2-数据集操作命令" class="headerlink" title="2.3.2.数据集操作命令"></a>2.3.2.数据集操作命令</h3><p>数据卷操作的基本语法如下：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker volume [COMMAND]<br></code></pre></td></tr></table></figure>

<p>docker volume 命令是数据卷操作，根据命令后跟随的 command 来确定下一步的操作：</p>
<ul>
<li>create 创建一个 volume</li>
<li>inspect 显示一个或多个 volume 的信息</li>
<li>ls 列出所有的 volume</li>
<li>prune 删除未使用的 volume</li>
<li>rm 删除一个或多个指定的 volume</li>
</ul>
<h3 id="2-3-3-创建和查看数据卷"><a href="#2-3-3-创建和查看数据卷" class="headerlink" title="2.3.3.创建和查看数据卷"></a>2.3.3.创建和查看数据卷</h3><p><strong>需求</strong>：创建一个数据卷，并查看数据卷在宿主机的目录位置</p>
<p>① 创建数据卷</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker volume create html<br></code></pre></td></tr></table></figure>

<p>② 查看所有数据</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker volume <span class="hljs-built_in">ls</span><br></code></pre></td></tr></table></figure>

<p>结果：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731173746910.png" alt="image-20210731173746910"></p>
<p>③ 查看数据卷详细信息卷</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker volume inspect html<br></code></pre></td></tr></table></figure>

<p>结果：</p>
<img src="http://blog.memory-life.xyz/image-20210731173809877.png" alt="image-20210731173809877" style="zoom:150%;" />

<p>可以看到，我们创建的 html 这个数据卷关联的宿主机目录为<code>/var/lib/docker/volumes/html/_data</code>目录。</p>
<p><strong>小结</strong>：</p>
<p>数据卷的作用：</p>
<ul>
<li>将容器与数据分离，解耦合，方便操作容器内数据，保证数据安全</li>
</ul>
<p>数据卷操作：</p>
<ul>
<li>docker volume create：创建数据卷</li>
<li>docker volume ls：查看所有数据卷</li>
<li>docker volume inspect：查看数据卷详细信息，包括关联的宿主机目录位置</li>
<li>docker volume rm：删除指定数据卷</li>
<li>docker volume prune：删除所有未使用的数据卷</li>
</ul>
<h3 id="2-3-4-挂载数据卷"><a href="#2-3-4-挂载数据卷" class="headerlink" title="2.3.4.挂载数据卷"></a>2.3.4.挂载数据卷</h3><p>我们在创建容器时，可以通过 -v 参数来挂载一个数据卷到某个容器内目录，命令格式如下：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run \<br>  --name mn \<br>  -v html:/root/html \<br>  -p 8080:80<br>  nginx \<br></code></pre></td></tr></table></figure>

<p>这里的-v 就是挂载数据卷的命令：</p>
<ul>
<li><code>-v html:/root/htm</code> ：把 html 数据卷挂载到容器内的/root/html 这个目录中</li>
</ul>
<h3 id="2-3-5-案例-给-nginx-挂载数据卷"><a href="#2-3-5-案例-给-nginx-挂载数据卷" class="headerlink" title="2.3.5.案例-给 nginx 挂载数据卷"></a>2.3.5.案例-给 nginx 挂载数据卷</h3><p><strong>需求</strong>：创建一个 nginx 容器，修改容器内的 html 目录内的 index.html 内容</p>
<p><strong>分析</strong>：上个案例中，我们进入 nginx 容器内部，已经知道 nginx 的 html 目录所在位置/usr/share/nginx/html ，我们需要把这个目录挂载到 html 这个数据卷上，方便操作其中的内容。</p>
<p><strong>提示</strong>：运行容器时使用 -v 参数挂载数据卷</p>
<p>步骤：</p>
<p>① 创建容器并挂载数据卷到容器内的 HTML 目录</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run --name mn -v html:/usr/share/nginx/html -p 80:80 -d nginx<br></code></pre></td></tr></table></figure>

<p>② 进入 html 数据卷所在位置，并修改 HTML 内容</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs sh"><span class="hljs-comment"># 查看html数据卷的位置</span><br>docker volume inspect html<br><span class="hljs-comment"># 进入该目录</span><br><span class="hljs-built_in">cd</span> /var/lib/docker/volumes/html/_data<br><span class="hljs-comment"># 修改文件</span><br>vi index.html<br></code></pre></td></tr></table></figure>

<h3 id="2-3-6-案例-给-MySQL-挂载本地目录"><a href="#2-3-6-案例-给-MySQL-挂载本地目录" class="headerlink" title="2.3.6.案例-给 MySQL 挂载本地目录"></a>2.3.6.案例-给 MySQL 挂载本地目录</h3><p>容器不仅仅可以挂载数据卷，也可以直接挂载到宿主机目录上。关联关系如下：</p>
<ul>
<li>带数据卷模式：宿主机目录 –&gt; 数据卷 —&gt; 容器内目录</li>
<li>直接挂载模式：宿主机目录 —&gt; 容器内目录</li>
</ul>
<p>如图：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731175155453.png" alt="image-20210731175155453"></p>
<p><strong>语法</strong>：</p>
<p>目录挂载与数据卷挂载的语法是类似的：</p>
<ul>
<li>-v [宿主机目录]:[容器内目录]</li>
<li>-v [宿主机文件]:[容器内文件]</li>
</ul>
<p><strong>需求</strong>：创建并运行一个 MySQL 容器，将宿主机目录直接挂载到容器</p>
<p>实现思路如下：</p>
<p>1）在将课前资料中的 mysql.tar 文件上传到虚拟机，通过 load 命令加载为镜像</p>
<p>2）创建目录/tmp/mysql/data</p>
<p>3）创建目录/tmp/mysql/conf，将课前资料提供的 hmy.cnf 文件上传到/tmp/mysql/conf</p>
<p>4）去 DockerHub 查阅资料，创建并运行 MySQL 容器，要求：</p>
<p>① 挂载/tmp/mysql/data 到 mysql 容器内数据存储目录</p>
<p>② 挂载/tmp/mysql/conf/hmy.cnf 到 mysql 容器的配置文件</p>
<p>③ 设置 MySQL 密码</p>
<h3 id="2-3-7-小结"><a href="#2-3-7-小结" class="headerlink" title="2.3.7.小结"></a>2.3.7.小结</h3><p>docker run 的命令中通过 -v 参数挂载文件或目录到容器中：</p>
<ul>
<li>-v volume 名称:容器内目录</li>
<li>-v 宿主机文件:容器内文</li>
<li>-v 宿主机目录:容器内目录</li>
</ul>
<p>数据卷挂载与目录直接挂载的</p>
<ul>
<li>数据卷挂载耦合度低，由 docker 来管理目录，但是目录较深，不好找</li>
<li>目录挂载耦合度高，需要我们自己管理目录，不过目录容易寻找查看</li>
</ul>
<h1 id="3-Dockerfile-自定义镜像"><a href="#3-Dockerfile-自定义镜像" class="headerlink" title="3.Dockerfile 自定义镜像"></a>3.Dockerfile 自定义镜像</h1><p>常见的镜像在 DockerHub 就能找到，但是我们自己写的项目就必须自己构建镜像了。</p>
<p>而要自定义镜像，就必须先了解镜像的结构才行。</p>
<h2 id="3-1-镜像结构"><a href="#3-1-镜像结构" class="headerlink" title="3.1.镜像结构"></a>3.1.镜像结构</h2><p>镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。</p>
<p>我们以 MySQL 为例，来看看镜像的组成结构：</p>
<p><img src="http://blog.memory-life.xyz/image-20210731175806273.png" alt="image-20210731175806273"></p>
<p>简单来说，镜像就是在系统函数库、运行环境基础上，添加应用程序文件、配置文件、依赖文件等组合，然后编写好启动脚本打包在一起形成的文件。</p>
<p>我们要构建镜像，其实就是实现上述打包的过程。</p>
<h2 id="3-2-Dockerfile-语法"><a href="#3-2-Dockerfile-语法" class="headerlink" title="3.2.Dockerfile 语法"></a>3.2.Dockerfile 语法</h2><p>构建自定义的镜像时，并不需要一个个文件去拷贝，打包。</p>
<p>我们只需要告诉 Docker，我们的镜像的组成，需要哪些 BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么，将来 Docker 会帮助我们构建镜像。</p>
<p>而描述上述信息的文件就是 Dockerfile 文件。</p>
<p><strong>Dockerfile</strong>就是一个文本文件，其中包含一个个的**指令(Instruction)**，用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层 Layer。</p>
<p><img src="http://blog.memory-life.xyz/image-20210731180321133.png" alt="image-20210731180321133"></p>
<p>更新详细语法说明，请参考官网文档： <a target="_blank" rel="noopener" href="https://docs.docker.com/engine/reference/builder">https://docs.docker.com/engine/reference/builder</a></p>
<h2 id="3-3-构建-Java-项目"><a href="#3-3-构建-Java-项目" class="headerlink" title="3.3.构建 Java 项目"></a>3.3.构建 Java 项目</h2><h3 id="3-3-1-基于-Ubuntu-构建-Java-项目"><a href="#3-3-1-基于-Ubuntu-构建-Java-项目" class="headerlink" title="3.3.1.基于 Ubuntu 构建 Java 项目"></a>3.3.1.基于 Ubuntu 构建 Java 项目</h3><p>需求：基于 Ubuntu 镜像构建一个新镜像，运行一个 java 项目</p>
<ul>
<li><p>步骤 1：新建一个空文件夹 docker-demo</p>
<img src="http://blog.memory-life.xyz/image-20210801101207444.png" alt="image-20210801101207444" style="zoom:150%;" /></li>
<li><p>步骤 2：拷贝课前资料中的 docker-demo.jar 文件到 docker-demo 这个目录</p>
<img src="http://blog.memory-life.xyz/image-20210801101314816.png" alt="image-20210801101314816" style="zoom:150%;" /></li>
<li><p>步骤 3：拷贝课前资料中的 jdk8.tar.gz 文件到 docker-demo 这个目录</p>
<img src="http://blog.memory-life.xyz/image-20210801101410200.png" alt="image-20210801101410200" style="zoom:150%;" /></li>
<li><p>步骤 4：拷贝课前资料提供的 Dockerfile 到 docker-demo 这个目录</p>
<img src="http://blog.memory-life.xyz/image-20210801101455590.png" alt="image-20210801101455590" style="zoom:150%;" />

<p>其中的内容如下：</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-comment"># 指定基础镜像</span><br><span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">16.04</span><br><span class="hljs-comment"># 配置环境变量，JDK的安装目录</span><br><span class="hljs-keyword">ENV</span> JAVA_DIR=/usr/local<br><br><span class="hljs-comment"># 拷贝jdk和java项目的包</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> ./jdk8.tar.gz <span class="hljs-variable">$JAVA_DIR</span>/</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> ./docker-demo.jar /tmp/app.jar</span><br><br><span class="hljs-comment"># 安装JDK</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">cd</span> <span class="hljs-variable">$JAVA_DIR</span> \</span><br><span class="language-bash"> &amp;&amp; tar -xf ./jdk8.tar.gz \</span><br><span class="language-bash"> &amp;&amp; <span class="hljs-built_in">mv</span> ./jdk1.8.0_144 ./java8</span><br><br><span class="hljs-comment"># 配置环境变量</span><br><span class="hljs-keyword">ENV</span> JAVA_HOME=$JAVA_DIR/java8<br><span class="hljs-keyword">ENV</span> PATH=$PATH:$JAVA_HOME/bin<br><br><span class="hljs-comment"># 暴露端口</span><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8090</span><br><span class="hljs-comment"># 入口，java项目的启动命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> java -jar /tmp/app.jar</span><br></code></pre></td></tr></table></figure></li>
<li><p>步骤 5：进入 docker-demo</p>
<p>将准备好的 docker-demo 上传到虚拟机任意目录，然后进入 docker-demo 目录下</p>
</li>
<li><p>步骤 6：运行命令：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker build -t javaweb:1.0 .<br></code></pre></td></tr></table></figure></li>
</ul>
<p>最后访问 <a target="_blank" rel="noopener" href="http://192.168.150.101:8090/hello/count%EF%BC%8C%E5%85%B6%E4%B8%AD%E7%9A%84ip%E6%94%B9%E6%88%90%E4%BD%A0%E7%9A%84%E8%99%9A%E6%8B%9F%E6%9C%BAip">http://192.168.150.101:8090/hello/count，其中的ip改成你的虚拟机ip</a></p>
<h3 id="3-3-2-基于-java8-构建-Java-项目"><a href="#3-3-2-基于-java8-构建-Java-项目" class="headerlink" title="3.3.2.基于 java8 构建 Java 项目"></a>3.3.2.基于 java8 构建 Java 项目</h3><p>虽然我们可以基于 Ubuntu 基础镜像，添加任意自己需要的安装包，构建镜像，但是却比较麻烦。所以大多数情况下，我们都可以在一些安装了部分软件的基础镜像上做改造。</p>
<p>例如，构建 java 项目的镜像，可以在已经准备了 JDK 的基础镜像基础上构建。</p>
<p>需求：基于 java:8-alpine 镜像，将一个 Java 项目构建为镜像</p>
<p>实现思路如下：</p>
<ul>
<li><p>① 新建一个空的目录，然后在目录中新建一个文件，命名为 Dockerfile</p>
</li>
<li><p>② 拷贝课前资料提供的 docker-demo.jar 到这个目录中</p>
</li>
<li><p>③ 编写 Dockerfile 文件：</p>
<ul>
<li><p>a ）基于 java:8-alpine 作为基础镜像</p>
</li>
<li><p>b ）将 app.jar 拷贝到镜像中</p>
</li>
<li><p>c ）暴露端口</p>
</li>
<li><p>d ）编写入口 ENTRYPOINT</p>
<p>内容如下：</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> java:<span class="hljs-number">8</span>-alpine<br><span class="hljs-keyword">COPY</span><span class="language-bash"> ./app.jar /tmp/app.jar</span><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8090</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> java -jar /tmp/app.jar</span><br></code></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>④ 使用 docker build 命令构建镜像</p>
</li>
<li><p>⑤ 使用 docker run 创建容器并运行</p>
</li>
</ul>
<h2 id="3-4-小结"><a href="#3-4-小结" class="headerlink" title="3.4.小结"></a>3.4.小结</h2><p>小结：</p>
<ol>
<li><p>Dockerfile 的本质是一个文件，通过指令描述镜像的构建过程</p>
</li>
<li><p>Dockerfile 的第一行必须是 FROM，从一个基础镜像来构建</p>
</li>
<li><p>基础镜像可以是基本操作系统，如 Ubuntu。也可以是其他人制作好的镜像，例如：java:8-alpine</p>
</li>
</ol>
<h1 id="4-Docker-Compose"><a href="#4-Docker-Compose" class="headerlink" title="4.Docker-Compose"></a>4.Docker-Compose</h1><p>Docker Compose 可以基于 Compose 文件帮我们快速的部署分布式应用，而无需手动一个个创建和运行容器！</p>
<p><img src="http://blog.memory-life.xyz/image-20210731180921742.png" alt="image-20210731180921742"></p>
<h2 id="4-1-初识-DockerCompose"><a href="#4-1-初识-DockerCompose" class="headerlink" title="4.1.初识 DockerCompose"></a>4.1.初识 DockerCompose</h2><p>Compose 文件是一个文本文件，通过指令定义集群中的每个容器如何运行。格式如下：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs json">version<span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;3.8&quot;</span><br> services<span class="hljs-punctuation">:</span><br>  mysql<span class="hljs-punctuation">:</span><br>    image<span class="hljs-punctuation">:</span> mysql<span class="hljs-punctuation">:</span><span class="hljs-number">5.7</span><span class="hljs-number">.25</span><br>    environment<span class="hljs-punctuation">:</span><br>     MYSQL_ROOT_PASSWORD<span class="hljs-punctuation">:</span> <span class="hljs-number">123</span><br>    volumes<span class="hljs-punctuation">:</span><br>     - <span class="hljs-string">&quot;/tmp/mysql/data:/var/lib/mysql&quot;</span><br>     - <span class="hljs-string">&quot;/tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf&quot;</span><br>  web<span class="hljs-punctuation">:</span><br>    build<span class="hljs-punctuation">:</span> .<br>    ports<span class="hljs-punctuation">:</span><br>     - <span class="hljs-string">&quot;8090:8090&quot;</span><br><br></code></pre></td></tr></table></figure>

<p>上面的 Compose 文件就描述一个项目，其中包含两个容器：</p>
<ul>
<li>mysql：一个基于<code>mysql:5.7.25</code>镜像构建的容器，并且挂载了两个目录</li>
<li>web：一个基于<code>docker build</code>临时构建的镜像容器，映射端口时 8090</li>
</ul>
<p>DockerCompose 的详细语法参考官网：<a target="_blank" rel="noopener" href="https://docs.docker.com/compose/compose-file/">https://docs.docker.com/compose/compose-file/</a></p>
<p>其实 DockerCompose 文件可以看做是将多个 docker run 命令写到一个文件，只是语法稍有差异。</p>
<h2 id="4-2-安装-DockerCompose"><a href="#4-2-安装-DockerCompose" class="headerlink" title="4.2.安装 DockerCompose"></a>4.2.安装 DockerCompose</h2><p>参考课前资料</p>
<h2 id="4-3-部署微服务集群"><a href="#4-3-部署微服务集群" class="headerlink" title="4.3.部署微服务集群"></a>4.3.部署微服务集群</h2><p><strong>需求</strong>：将之前学习的 cloud-demo 微服务集群利用 DockerCompose 部署</p>
<p><strong>实现思路</strong>：</p>
<p>① 查看课前资料提供的 cloud-demo 文件夹，里面已经编写好了 docker-compose 文件</p>
<p>② 修改自己的 cloud-demo 项目，将数据库、nacos 地址都命名为 docker-compose 中的服务名</p>
<p>③ 使用 maven 打包工具，将项目中的每个微服务都打包为 app.jar</p>
<p>④ 将打包好的 app.jar 拷贝到 cloud-demo 中的每一个对应的子目录中</p>
<p>⑤ 将 cloud-demo 上传至虚拟机，利用 docker-compose up -d 来部署</p>
<h3 id="4-3-1-compose-文件"><a href="#4-3-1-compose-文件" class="headerlink" title="4.3.1.compose 文件"></a>4.3.1.compose 文件</h3><p>查看课前资料提供的 cloud-demo 文件夹，里面已经编写好了 docker-compose 文件，而且每个微服务都准备了一个独立的目录：</p>
<img src="http://blog.memory-life.xyz/image-20210731181341330.png" alt="image-20210731181341330" style="zoom:150%;" />

<p>内容如下：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">&quot;3.2&quot;</span><br><br><span class="hljs-attr">services:</span><br>  <span class="hljs-attr">nacos:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">nacos/nacos-server</span><br>    <span class="hljs-attr">environment:</span><br>      <span class="hljs-attr">MODE:</span> <span class="hljs-string">standalone</span><br>    <span class="hljs-attr">ports:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">&quot;8848:8848&quot;</span><br>  <span class="hljs-attr">mysql:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:5.7.25</span><br>    <span class="hljs-attr">environment:</span><br>      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-number">123</span><br>    <span class="hljs-attr">volumes:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">&quot;$PWD/mysql/data:/var/lib/mysql&quot;</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">&quot;$PWD/mysql/conf:/etc/mysql/conf.d/&quot;</span><br>  <span class="hljs-attr">userservice:</span><br>    <span class="hljs-attr">build:</span> <span class="hljs-string">./user-service</span><br>  <span class="hljs-attr">orderservice:</span><br>    <span class="hljs-attr">build:</span> <span class="hljs-string">./order-service</span><br>  <span class="hljs-attr">gateway:</span><br>    <span class="hljs-attr">build:</span> <span class="hljs-string">./gateway</span><br>    <span class="hljs-attr">ports:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">&quot;10010:10010&quot;</span><br></code></pre></td></tr></table></figure>

<p>可以看到，其中包含 5 个 service 服务：</p>
<ul>
<li><code>nacos</code>：作为注册中心和配置中心<ul>
<li><code>image: nacos/nacos-server</code>： 基于 nacos/nacos-server 镜像构建</li>
<li><code>environment</code>：环境变量<ul>
<li><code>MODE: standalone</code>：单点模式启动</li>
</ul>
</li>
<li><code>ports</code>：端口映射，这里暴露了 8848 端口</li>
</ul>
</li>
<li><code>mysql</code>：数据库<ul>
<li><code>image: mysql:5.7.25</code>：镜像版本是 mysql:5.7.25</li>
<li><code>environment</code>：环境变量<ul>
<li><code>MYSQL_ROOT_PASSWORD: 123</code>：设置数据库 root 账户的密码为 123</li>
</ul>
</li>
<li><code>volumes</code>：数据卷挂载，这里挂载了 mysql 的 data、conf 目录，其中有我提前准备好的数据</li>
</ul>
</li>
<li><code>userservice</code>、<code>orderservice</code>、<code>gateway</code>：都是基于 Dockerfile 临时构建的</li>
</ul>
<p>查看 mysql 目录，可以看到其中已经准备好了 cloud_order、cloud_user 表：</p>
<p><img src="http://blog.memory-life.xyz/image-20210801095205034.png" alt="image-20210801095205034"></p>
<p>查看微服务目录，可以看到都包含 Dockerfile 文件：</p>
<img src="http://blog.memory-life.xyz/image-20210801095320586.png" alt="image-20210801095320586" style="zoom:150%;" />

<p>内容如下：</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> java:<span class="hljs-number">8</span>-alpine<br><span class="hljs-keyword">COPY</span><span class="language-bash"> ./app.jar /tmp/app.jar</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> java -jar /tmp/app.jar</span><br></code></pre></td></tr></table></figure>

<h3 id="4-3-2-修改微服务配置"><a href="#4-3-2-修改微服务配置" class="headerlink" title="4.3.2.修改微服务配置"></a>4.3.2.修改微服务配置</h3><p>因为微服务将来要部署为 docker 容器，而容器之间互联不是通过 IP 地址，而是通过容器名。这里我们将 order-service、user-service、gateway 服务的 mysql、nacos 地址都修改为基于容器名的访问。</p>
<p>如下所示：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">spring:</span><br>  <span class="hljs-attr">datasource:</span><br>    <span class="hljs-attr">url:</span> <span class="hljs-string">jdbc:mysql://mysql:3306/cloud_order?useSSL=false</span><br>    <span class="hljs-attr">username:</span> <span class="hljs-string">root</span><br>    <span class="hljs-attr">password:</span> <span class="hljs-number">123</span><br>    <span class="hljs-attr">driver-class-name:</span> <span class="hljs-string">com.mysql.jdbc.Driver</span><br>  <span class="hljs-attr">application:</span><br>    <span class="hljs-attr">name:</span> <span class="hljs-string">orderservice</span><br>  <span class="hljs-attr">cloud:</span><br>    <span class="hljs-attr">nacos:</span><br>      <span class="hljs-attr">server-addr:</span> <span class="hljs-string">nacos:8848</span> <span class="hljs-comment"># nacos服务地址</span><br></code></pre></td></tr></table></figure>

<h3 id="4-3-3-打包"><a href="#4-3-3-打包" class="headerlink" title="4.3.3.打包"></a>4.3.3.打包</h3><p>接下来需要将我们的每个微服务都打包。因为之前查看到 Dockerfile 中的 jar 包名称都是 app.jar，因此我们的每个微服务都需要用这个名称。</p>
<p>可以通过修改 pom.xml 中的打包名称来实现，每个微服务都需要修改：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span><br>  <span class="hljs-comment">&lt;!-- 服务打包的最终名称 --&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>app<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span><br>  <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>打包后：</p>
<img src="http://blog.memory-life.xyz/image-20210801095951030.png" alt="image-20210801095951030" style="zoom:150%;" />

<h3 id="4-3-4-拷贝-jar-包到部署目录"><a href="#4-3-4-拷贝-jar-包到部署目录" class="headerlink" title="4.3.4.拷贝 jar 包到部署目录"></a>4.3.4.拷贝 jar 包到部署目录</h3><p>编译打包好的 app.jar 文件，需要放到 Dockerfile 的同级目录中。注意：每个微服务的 app.jar 放到与服务名称对应的目录，别搞错了。</p>
<p>user-service：</p>
<img src="http://blog.memory-life.xyz/image-20210801100201253.png" alt="image-20210801100201253" style="zoom:150%;" />

<p>order-service：</p>
<img src="http://blog.memory-life.xyz/image-20210801100231495.png" alt="image-20210801100231495" style="zoom:150%;" />

<p>gateway：</p>
<img src="http://blog.memory-life.xyz/image-20210801100308102.png" alt="image-20210801100308102" style="zoom:150%;" />

<h3 id="4-3-5-部署"><a href="#4-3-5-部署" class="headerlink" title="4.3.5.部署"></a>4.3.5.部署</h3><p>最后，我们需要将文件整个 cloud-demo 文件夹上传到虚拟机中，理由 DockerCompose 部署。</p>
<p>上传到任意目录：</p>
<img src="http://blog.memory-life.xyz/image-20210801100955653.png" alt="image-20210801100955653" style="zoom:150%;" />

<p>部署：</p>
<p>进入 cloud-demo 目录，然后运行下面的命令：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker-compose up -d<br></code></pre></td></tr></table></figure>

<h1 id="5-Docker-镜像仓库"><a href="#5-Docker-镜像仓库" class="headerlink" title="5.Docker 镜像仓库"></a>5.Docker 镜像仓库</h1><h2 id="5-1-搭建私有镜像仓库"><a href="#5-1-搭建私有镜像仓库" class="headerlink" title="5.1.搭建私有镜像仓库"></a>5.1.搭建私有镜像仓库</h2><p>参考课前资料《CentOS7 安装 Docker.md》</p>
<h2 id="5-2-推送、拉取镜像"><a href="#5-2-推送、拉取镜像" class="headerlink" title="5.2.推送、拉取镜像"></a>5.2.推送、拉取镜像</h2><p>推送镜像到私有镜像服务必须先 tag，步骤如下：</p>
<p>① 重新 tag 本地镜像，名称前缀为私有仓库的地址：192.168.150.101:8080/</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker tag nginx:latest 192.168.150.101:8080/nginx:1.0<br></code></pre></td></tr></table></figure>

<p>② 推送镜像</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker push 192.168.150.101:8080/nginx:1.0<br></code></pre></td></tr></table></figure>

<p>③ 拉取镜像</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker pull 192.168.150.101:8080/nginx:1.0<br></code></pre></td></tr></table></figure>

                
              </div>
            
            <hr/>
            <div>
              <!-- 文章页面 - 底部标签 -->
<div class="post-metas my-3">
  
  <div class="post-meta mr-3 d-flex align-items-center">
    <i class="iconfont icon-category"></i>
    <!-- 归档页 - 文章列表 -->


<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/blog/categories/%E4%BB%A3%E7%A0%81%E9%94%8B%E8%8A%92/" class="category-chain-item">代码锋芒</a>
  
  
    <span>></span>
    
  <a href="/blog/categories/%E4%BB%A3%E7%A0%81%E9%94%8B%E8%8A%92/%E9%83%A8%E7%BD%B2%E4%B9%8B%E9%81%93/" class="category-chain-item">部署之道</a>
  
  

  

      </span>
    
  
</span>

  </div>
   
  <div class="post-meta">
    <i class="iconfont icon-tags"></i>
    
    <a href="/blog/tags/%E7%BB%8F%E9%AA%8C/">#经验</a>
    
    <a href="/blog/tags/Docker/">#Docker</a>
    
  </div>
  
</div>


              <!-- 文章页面 - 底部标签下方 -->

  
  <div class="license-box my-3">
    <div class="license-title">
      <div>Docker入门与实践：快速打造高效网站部署环境</div>
      <div>https://test.atomgit.net/blog/2023/07/11/Docker 入门与实践：快速打造高效网站部署环境/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>Memory</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2023年7月11日</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>更新于</div>
          <div>2025年6月5日</div>
        </div>
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/blog/2023/07/11/%E9%A1%B9%E7%9B%AE%E5%BF%97%E5%BD%95%EF%BC%9AMemory%20API%20%E6%8E%A5%E5%8F%A3%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3/" title="项目志录：Memory API 接口开放平台开发文档">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">项目志录：Memory API 接口开放平台开发文档</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/blog/2023/07/11/%E4%BB%8EIP%E5%88%B0Ping%E5%91%BD%E4%BB%A4%EF%BC%9A%E4%BA%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E7%9A%84%E5%9F%BA%E7%A1%80/" title="从IP到Ping命令：了解计算机网络连接的基础">
                        <span class="hidden-mobile">从IP到Ping命令：了解计算机网络连接的基础</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            <!-- 文章页 - 评论上方 -->

  
  
    <article id="comments">
      
  <div id="valine"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#valine', function() {
      Fluid.utils.createScript('https://cdn.jsdelivr.net/gh/HCLonely/Valine@latest/dist/Valine.min.js', function() {
        var options = Object.assign(
          {"appId":"T1hUHH9Ks1ggG9DBE3HgUPpV-gzGzoHsz","appKey":"XFkgzzvzNo3J3uNCbBiSOFKc","path":"window.location.pathname","placeholder":"填取QQ号和邮箱后评论，支持读取头像及消息提醒，留下点什么叭... ᶘ ᵒᴥᵒᶅ","avatar":"Gravatar","meta":["nick","mail","link"],"requiredFields":[],"pageSize":10,"lang":"zh-CN","highlight":true,"recordIP":false,"serverURLs":"https://t1huhh9k.lc-cn-n1-shared.com","emojiCDN":null,"emojiMaps":null,"enableQQ":true,"master":"8c9b6d6637904da62d74d019cc6982de","friends":"0188229a9cfc284176ea9135cb9514cc","visitor":true},
          {
            el: "#valine",
            path: window.location.pathname,
            app_id: "",
            app_key: "",
            placeholder: "填取QQ号和邮箱后评论，支持读取头像及消息提醒，留下点什么叭... ᶘ ᵒᴥᵒᶅ",
            avatar: "Gravatar",
            meta: ["nick","mail","link"],
            pageSize: "10",
            lang: "zh-CN",
            highlight: true,
            recordIP: false,
            serverURLs: "https://t1huhh9k.lc-cn-n1-shared.com",

            // 设置Bilibili表情包地址
            emojiCDN: '//i0.hdslb.com/bfs/emote/', 
            // 表情title和图片映射
            emojiMaps: {
                "tv_白眼": "48f75163437445665a9be80bb316e4cb252c5415.gif@48w_48h.webp",
                "tv_doge": "302d6c88c63ed162c81a49cafe7ed2709e6fb955.gif@48w_48h.webp",
                "tv_坏笑": "5d2572efd09aab5dde9e2a198bb3f9ac1e2a982e.gif@48w_48h.webp",
                "tv_难过": "9c6b41008a67755410f712334c64313df5f91b3f.gif@48w_48h.webp",
                "tv_生气": "1902a5a2df5b5c931d88c12f0feb264b1e109d0d.gif@48w_48h.webp",
                "tv_委屈": "af5a5853edb43a8178a8cb5df707fa5e88143699.gif@48w_48h.webp",
                "tv_斜眼笑": "c66568b471192ca1f62f6ed4384dc1b283ab7508.gif@48w_48h.webp",
                "tv_呆": "d3fa91e4db9215eb1e20ab9da44f1214aa4bda7b.gif@48w_48h.webp",
                "tv_发怒": "3959eb81b952e4fa8d269d98f9e3639172d84073.gif@48w_48h.webp",
                "tv_呕吐": "db58e9442aae26694af18cc1683607cca3a16763.gif@48w_48h.webp",
                "tv_思考": "b63f9146bfd985af014f8d6d4bdb498805be48f9.gif@48w_48h.webp",
                "tv_微笑": "b98656855d782f61cb8edc7f7fca6563ecafff7e.gif@48w_48h.webp",
                "tv_疑问": "fce1b1a0f3b0e39a2dc16a18508dba7b91e929f4.gif@48w_48h.webp",
                "tv_大哭": "cba61f05f3039b02a7ffc0dfcd9d7995df9fdd74.gif@48w_48h.webp",
                "tv_鼓掌": "be106e6b265883a9f28fbe10f7b765701e2618d4.gif@48w_48h.webp",
                "tv_抠鼻": "696d9f93e722144dc2a78aeffc569418fdf3d565.gif@48w_48h.webp",
                "tv_亲亲": "3534ea44ab74bd20352b88c245a06c4b4c46d271.gif@48w_48h.webp",
                "tv_调皮": "fcd967395fd14e4dd5829fa7e8a967ce23205e52.gif@48w_48h.webp",
                "tv_笑哭": "1c2fd1e8c9dde12812f86e5d4cbddd8993d98082.gif@48w_48h.webp",
                "tv_晕": "030040ec5c9ddc9e3d067658c4139e7314ab42f8.gif@48w_48h.webp",
                "tv_点赞": "30ecff401245fb56bcc1cf588d1809ac1ab1607c.gif@48w_48h.webp",
                "tv_害羞": "411a3e459e8580f5bfd9f639a408247c4b509935.gif@48w_48h.webp",
                "tv_睡着": "3c8b5e293261287a6203597e29b3de07df4d18c6.gif@48w_48h.webp",
                "tv_色": "a0c6d99ab0ab63b8648f5283ff72cec04b604828.gif@48w_48h.webp",
                "tv_吐血": "e17e4539e169d14a3389ff147afea760cebe5de5.gif@48w_48h.webp",
                "tv_无奈": "eb4cb5f07cfd177c7e6a7914316717e56d9cc1d0.gif@48w_48h.webp",
                "tv_再见": "344f61609ecce2008520dc8a977b6169215748a9.gif@48w_48h.webp",
                "tv_流汗": "390bccec65eaff536bd5bb2a0c5b8b0bdea47334.gif@48w_48h.webp",
                "tv_偷笑": "7f11e6f7f63e79112b833bd41fa13a83d7cd8474.gif@48w_48h.webp",
                "tv_抓狂":"a476b93ecd8e94ac3257323fd822f91cef212de2.gif@48w_48h.webp",
                "tv_黑人问号":"b609adf664be33224a9923262031165ae3e34cd2.gif@48w_48h.webp",
                "tv_困":"91c2bf34ecf842d7016c01d841db3d4074bd281f.gif@48w_48h.webp",
                "tv_打脸":"b0fad4856e59c1240e448437da3287bb5ce547e5.gif@48w_48h.webp",
                "tv_闭嘴":"a3fc5388b09e945be3f18fe23bfed5874a0285b7.gif@48w_48h.webp",
                "tv_鄙视":"293b5d459e6264ecf314d20937a936fa672ccd1e.gif@48w_48h.webp",
                "tv_腼腆":"30984e8264324f901d19bea85dada7103b695534.gif@48w_48h.webp",
                "tv_馋":"2525c5703c594e5f0752f68db8948773caebde47.gif@48w_48h.webp",
                "tv_可爱":"f92d20f76258bc5f33fc9d7c5e2a1d41fef19a7c.gif@48w_48h.webp",
                "tv_发财":"76131e52c9b033681b4c896c6024d29ef7ec7ec2.gif@48w_48h.webp",
                "tv_生病":"beb94829fe04f1a41bd6ca611e1f6ca9ca169afa.gif@48w_48h.webp",
                "tv_流鼻血":"8ef473f74a849420da712487b2f56ecca1f695f5.gif@48w_48h.webp",
                "tv_尴尬":"e0b84ef5ee3e5b8978e584c7c5a6550c51d15f84.gif@48w_48h.webp",
                "tv_大佬":"14ca0c05382b8741940942b2430b7a8d55c02f7e.gif@48w_48h.webp",
                "tv_流泪":"7e71cde7858f0cd50d74b0264aa26db612a8a167.png@48w_48h.webp",
                "tv_冷漠":"b9cbc755c2b3ee43be07ca13de84e5b699a3f101.png@48w_48h.webp",
                "tv_皱眉":"72ccad6679fea0d14cce648b4d818e09b8ffea2d.png@48w_48h.webp",
                "tv_鬼脸":"0ffbbddf8a94d124ca2f54b360bbc04feb6bbfea.png@48w_48h.webp",
                "tv_调侃":"4bc022533ef31544ca0d72c12c808cf4a1cce3e3.png@48w_48h.webp",
                "tv_目瞪口呆":"0b8cb81a68de5d5365212c99375e7ace3e7891b7.png@48w_48h.webp",
            },

            master: "8c9b6d6637904da62d74d019cc6982de",
            friends: "0188229a9cfc284176ea9135cb9514cc",
            tagMeta: ["博主","友人","访客"],
            visitor: true // 阅读量统计
          }
        )
        new Valine(options);
        Fluid.utils.waitElementVisible('#valine .vcontent', () => {
          var imgSelector = '#valine .vcontent img:not(.vemoji)';
          Fluid.plugins.imageCaption(imgSelector);
          Fluid.plugins.fancyBox(imgSelector);
        })
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


    </article>
  


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      <!-- 文章页面 - 右侧目录 -->

  <aside class="sidebar" style="margin-left: -1rem">
    <!-- 文章页面 - 右侧目录上方 -->
<div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>



    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <!-- 博客 - 搜索框 -->
<div
  class="modal fade"
  id="modalSearch"
  tabindex="-1"
  role="dialog"
  aria-labelledby="ModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">
          搜索
        </h4>
        <button
          type="button"
          id="local-search-close"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input
            type="text"
            id="local-search-input"
            class="form-control validate"
          />
          <label data-error="x" data-success="v" for="local-search-input"
            >关键词</label
          >
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
        <div class="modal fade" id="modalNotice" tabindex="-1" role="dialog" aria-hidden="true"
     style="font-family: 'Ma Shan Zheng', cursive; color: #ffffff;">
    <div class="modal-dialog modal-dialog-scrollable" role="document"
         style="font-family: 'Ma Shan Zheng', cursive;">
        <div class="modal-content" style="border-radius: 6px;">
            <!-- 公告头部 - 响应式设计 -->
            <div class="modal-header text-center"
                 style="padding: 1rem 1.5rem;border-bottom: 1px solid rgba(255,255,255,0.2)">
                <h4 class="modal-title w-100 font-weight-bold"
                    style="font-family: 'Microsoft YaHei', sans-serif;letter-spacing: 1px;text-shadow: 1px 1px 2px rgba(0,0,0,0.2);color: #ffffff;
                           font-size: 1.5rem; /* 默认PC端大小 */
                           /* 移动端适配 */
                           @media (max-width: 768px) {
                               font-size: 1.2rem;
                           }">
                    <div class="notice-title">
                        <i class="fas fa-bullhorn mr-2"> 围栏告示</i>
                    </div>
                    <small style="display: block; font-family: 'STKaiti', serif; font-size: 0.6em; color: #a0a0a0; margin-top: 3px;">
                        旧梦轻拾 · 谨识
                    </small>
                </h4>
            </div>

            <!-- 公告内容区 - 响应式设计 -->
            <div class="modal-body"
                 style="padding: 2rem; /* PC端 */
                        max-height: 70vh;
                        overflow-y: auto;
                        /* 移动端适配 */
                        @media (max-width: 768px) {
                            padding: 1rem;
                            max-height: 60vh;
                        }">
                <!-- 图片容器（响应式设计） -->
                <!--                <div class="announcement-hero"-->
                <!--                     style="margin-bottom: 2rem; /* PC端 */-->
                <!--                            /* 移动端适配 */-->
                <!--                            @media (max-width: 768px) {-->
                <!--                                margin-bottom: 1rem;-->
                <!--                            }">-->
                <!--                    <img src="http://blog.memory-life.icu/%E3%80%90%E5%93%B2%E9%A3%8E%E5%A3%81%E7%BA%B8%E3%80%91%E5%8A%A8%E6%BC%AB-%E5%A4%95%E9%98%B3%E9%93%81%E8%BD%A8.jpg"-->
                <!--                         alt="时光溯洄题图"-->
                <!--                         style="width: 100%; -->
                <!--                                max-height: 400px; /* PC端 */-->
                <!--                                object-fit: cover;-->
                <!--                                border-radius: 4px; -->
                <!--                                box-shadow: 0 2px 12px rgba(0,0,0,0.1);-->
                <!--                                /* 移动端适配 */-->
                <!--                                @media (max-width: 768px) {-->
                <!--                                    max-height: 30vh;-->
                <!--                                }"-->
                <!--                         loading="lazy">-->
                <!--                </div>-->

                <!-- 静态公告列表 - 响应式设计 -->
                <div class="announcement-list">
                    <div class="announcement-item"
                         style="margin-bottom: 2rem; /* PC端 */
                                padding: 2rem;
                                background: rgba(255,255,255,0.05);
                                border-radius: 8px;
                                /* 移动端适配 */
                                @media (max-width: 768px) {
                                    margin-bottom: 1rem;
                                    padding: 1rem;
                                }">
                        <h2 style="color: #d38532;
                                  font-weight: 600;
                                  font-size: 1.5rem; /* PC端 */
                                  margin-bottom: 1.2rem;
                                  letter-spacing: 0.5px;
                                  /* 移动端适配 */
                                  @media (max-width: 768px) {
                                      font-size: 1.2rem;
                                      margin-bottom: 1rem;
                                  }">
                            <i class="fas fa-calendar-check mr-2"></i>时光溯洄
                            <small style="display: block; font-size: 0.6em; color: #b8b8b8;text-align: right;">——
                                晨昏往事</small>
                        </h2>
                        <div style="color: #e0e0e0;
                                  line-height: 1.8; /* PC端 */
                                  font-size: 1.05rem;
                                  letter-spacing: 0.3px;
                                  /* 移动端适配 */
                                  @media (max-width: 768px) {
                                      line-height: 1.6;
                                      font-size: 0.95rem;
                                  }">
                            <!-- 内容保持不变 -->
                            <p style="margin-bottom: 1rem; text-indent: 2em;">你好。</p>
                            <!-- 其余段落内容... -->
                            <p style="margin-bottom: 1rem; text-indent: 2em;">
                                建站后的第813天，在百忙之中总算又能抽出时间来，对整个博客站点功能做整体的规划及优化完善。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em;">
                                在刚刚过去的几年时间里，往事皆以笔墨挥毫于时光素笺之上，数百天如一日，故事的书写从未间断过。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em; font-style: italic; color: #b8b8b8;">
                                时光悠悠，日月如流，过往的蹉跎岁月总在不经意间在心间回眸。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em; font-weight: 500; color: #ffffff;">
                                俯仰之间，轻舟已过万重山。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em; font-weight: 500; color: #ffffff;">
                                蹉跎之处，往事皆成云烟散。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em;">
                                这几年的时光过得太快了，好像过去这段岁月里的所有事情都发生在一瞬间。</p>
                            <p style="margin-bottom: 1rem; text-indent: 2em;">
                                这几年的时光同样太久了，久到那些时日里仿佛囊括了自己的整个前半生。</p>
                            <p style="margin-bottom: 0; text-align: right; font-size: 0.95rem; color: #a0a0a0;">——
                                八百余个昼夜，当时只道是地久天长，如今回望，不过浮光掠影间的一瞬。</p>
                        </div>
                    </div>

                    <!-- 第二个公告项 - 响应式设计 -->
                    <div class="announcement-item"
                         style="margin-bottom: 2rem; /* PC端 */
                                padding: 2rem;
                                background: rgba(255,255,255,0.05);
                                border-radius: 8px;
                                /* 移动端适配 */
                                @media (max-width: 768px) {
                                    margin-bottom: 1rem;
                                    padding: 1rem;
                                }">
                        <h2 style="color: #6cc70b;
                                  font-weight: 600;
                                  font-size: 1.5rem; /* PC端 */
                                  margin-bottom: 1.2rem;
                                  letter-spacing: 0.5px;
                                  /* 移动端适配 */
                                  @media (max-width: 768px) {
                                      font-size: 1.2rem;
                                      margin-bottom: 1rem;
                                  }">
                            <i class="fas fa-book-open mr-2"></i>墨痕新注
                            <small style="display: block; font-size: 0.6em; color: #b8b8b8;text-align: right;">——
                                待起之章</small>
                        </h2>
                        <div style="color: #e0e0e0;
                                  line-height: 1.8; /* PC端 */
                                  font-size: 1.05rem;
                                  letter-spacing: 0.3px;
                                  /* 移动端适配 */
                                  @media (max-width: 768px) {
                                      line-height: 1.6;
                                      font-size: 0.95rem;
                                  }">
                            <!-- 列表内容 - 响应式设计 -->
                            <ul style="padding-left: 1.8rem; /* PC端 */
                                      margin-bottom: 1.5rem;
                                      /* 移动端适配 */
                                      @media (max-width: 768px) {
                                          padding-left: 1.5rem;
                                          margin-bottom: 1.2rem;
                                      }">
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">溯源计划：</span>新增博文"溯源计划"，旨在用先进的数字技术留住过去的旧时光，让家族的记忆在数字云端生长发芽，全站博文数量已达90+。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">围栏告示：</span>自去年夏天站点新增了“评论回复”功能后，至今时隔十余月，在芒种前夕本站久违地上线“围栏告示”功能，本公告栏会不定时更新，持续跟进记录最新站点功能调整日志，更多精彩内容请敬请期待。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">图片查看：</span>最近几周时间里，考虑到图文流量费用收取问题，暂时关闭了七牛云对象存储私有空间访问权限，故博文内的图文无法正常预览，择日考虑开启访问权限。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">壁纸下载：</span>后续计划实现壁纸下载功能，均为个人收集的共150+超高分辨率精美壁纸，提供在线预览以及下载功能。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">阅读体验：</span>规划完善文章内分页功能，并提供“最近更新”的文章列表，计划收录更新率较高的文章，譬如：阳台日记、叙事之外、岁月如歌、游戏人生等等，尽可能多的提升在线浏览和阅读体验。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">友链完善：</span>持续优化完善友链页面，整理归档个人常用的高质量网站合集，无偿分享给有缘人。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">音乐餐厅：</span>历经十余小时不间断调研和尝试，本站成功上线”音乐餐厅”功能，目前仅收录了个人在QQ音乐平台积累的两份歌单，再匆忙也要记得点播一首喜欢的音乐，没有音乐熏陶的心灵终究是充满缺憾的。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">三言两语：</span>每张照片都是时光的便签，随手一贴就记下了那天，本站结合Mamos实现并注入留言板功能，随缘记录那些藏在照片背后的故事。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">旧梦轻拾：</span>更新全站博客文章所属分类，共设有代码锋芒、部署之道、旧梦轻拾、人间片刻等十余种分类。
                                </li>
                                <li style="margin-bottom: 0.8rem; /* PC端 */
                                         position: relative;
                                         list-style-type: none;
                                         /* 移动端适配 */
                                         @media (max-width: 768px) {
                                             margin-bottom: 0.6rem;
                                         }">
                                    <span style="position: absolute;
                                               left: -1.8rem; /* PC端 */
                                               color: #6cc70b;
                                               /* 移动端适配 */
                                               @media (max-width: 768px) {
                                                   left: -1.5rem;
                                               }">◆</span>
                                    <span style="font-weight: bolder;">方寸之间：</span>博客应用版发布，更便捷的阅读体验来了！现已正式推出独立的桌面应用程序与移动端应用程序，暂时通过网盘和代码库提供安装包。
                                </li>
                                <p style="margin-bottom: 0; text-align: right; font-size: 0.9rem; color: #8a8a8a;">
                                    此公告最后更新于：<span style="color: #6cc70b;">2025/09/30晚</span>
                                </p>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 公告页脚 - 响应式设计 -->
            <div class="modal-footer"
                 style="border-top: 1px solid rgba(255,255,255,0.2);
                        padding: 1rem 1.5rem; /* PC端 */
                        justify-content: space-between;
                        /* 移动端适配 */
                        @media (max-width: 768px) {
                            padding: 0.8rem;
                        }">
                <small style="color: #ffffff;
                            font-size: 0.9rem; /* PC端 */
                            /* 移动端适配 */
                            @media (max-width: 768px) {
                                font-size: 0.8rem;
                            }">
                    <i class="iconfont icon-pen"></i>
                    <i class="fas fa-info-circle mr-1"></i>芒种前夕 · 旅途第813天
                    · 2025/05/28
                </small>
                <button id="confirm-btn" type="button" class="btn btn-sm" data-dismiss="modal"
                        style="background: #a0a0a0;
                               color: #ffffff;
                               border-radius: 4px;
                               padding: 0.5rem 1.2rem; /* PC端 */
                               border: none;
                               font-size: 0.9rem;
                               /* 移动端适配 */
                               @media (max-width: 768px) {
                                   padding: 0.3rem 0.8rem;
                                   font-size: 0.85rem;
                               }">
                    <i class="fas fa-check mr-1" style="color: #ffffff;">心已阅</i>
                </button>
            </div>
        </div>
    </div>
</div>

<style>
  .notice-title {
    display: flex;
    align-items: center;
    white-space: nowrap;
  }

  .notice-title:before,
  .notice-title:after {
    content: "";
    flex: 1;
    height: 1px;
    background: #ddd; /* 横线颜色 */
    margin: 0 10px; /* 横线与文字的间距 */
  }
</style>


<style>
  /* 响应式模态框宽度 */
  @media (min-width: 992px) {
    #modalNotice .modal-dialog {
      max-width: 800px;
    }
  }

  @media (max-width: 991px) {
    #modalNotice .modal-dialog {
      margin: 0.5rem auto;
    }
  }
</style>

<script>
  // 页面加载完成后执行
  document.addEventListener('DOMContentLoaded', function () {
    // 检查是否首次访问
    if (!localStorage.getItem('hasShownPopup')) {
      // 动态加载notice.ejs内容
      fetch('_partials/notice.ejs')  // 替换为实际路径
        .then(response => response.text())
        .then(html => {
          // 插入到页面body末尾
          document.body.insertAdjacentHTML('beforeend', html);

          // 手动初始化Bootstrap模态框
          $('#modalNotice').modal('show');

          // 标记为已显示
          localStorage.setItem('hasShownPopup', 'true');

          // 监听关闭事件
          $('#modalNotice').on('hidden.bs.modal', function () {
            // 可选的后续处理
          });
        })
        .catch(error => {
          console.error('加载公告栏失败:', error);
          // 备用方案：显示简单弹窗
          const fallbackHTML = `
                <div class="modal-backdrop" style="/* 样式 */">
                    <div class="modal-content">/* 内容 */</div>
                </div>`;
          document.body.insertAdjacentHTML('beforeend', fallbackHTML);
        });
    }
  });
</script>

    

    
  </main>

  <footer>
    <!-- 博客 - 页脚 -->
<div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.fluid-dev.com/docs/guide/" target="_blank" rel="nofollow noopener"> <span>Memory | 个人文档站点</span> </a>
<i class="iconfont icon-love"></i> <a href="https://hexo.fluid-dev.com/docs/guide/" target="_blank" rel="nofollow noopener"> <span>配置指南 | Hexo Fluid 用户手册</span> </a> 
    </div>
  

  

  
    <!-- 备案信 ICP for China -->
    <div class="beian">
  <span>
    <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">
      京ICP证123456号
    </a>
  </span>
  
    
      <span>
        <a
          href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=12345678"
          rel="nofollow noopener"
          class="beian-police"
          target="_blank"
        >
          
            <span style="visibility: hidden; width: 0">|</span>
            <img src="/blog/img/police_beian.png" alt="police-icon"/>
          
          <span>京公网安备12345678号</span>
        </a>
      </span>
    
  
</div>

  

  

</div>

<!-- 评论框美化 -->
<style>
    #comments .veditor{
        min-height: 20vh;
        background-image: url(http://blog.memory-life.icu/pathway0716.jpg);
        background-size: contain;
        background-repeat: no-repeat;
        background-position: right;
        background-color: rgba(255,255,255,0);
        resize: none;}
</style>

<script>
    //   自定义邮箱审核规则
    document.body.addEventListener('click', function(e) {
        if (e.target.classList.contains('vsubmit')) {
            const email = document.querySelector('input[type=email]');
            const nick = document.querySelector('input[name=nick]');
            const reg = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
            if (!email.value || !nick.value || !reg.test(email.value)) {
                const str = `<div class="valert text-center"><div class="vtext">请填写正确的昵称和邮箱！</div></div>`;
                const vmark = document.querySelector('.vmark');
                vmark.innerHTML = str;
                vmark.style.display = 'block';
                setTimeout(function() {
                    vmark.style.display = 'none';
                    vmark.innerHTML = '';
                }, 2500);
            }
        }
    })
</script>



  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/blog/js/events.js" ></script>
<script  src="/blog/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>







  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/blog/js/local-search.js" ></script>

  <script defer src="/blog/js/leancloud.js" ></script>




    
<script src="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>



<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/blog/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
